summaryrefslogtreecommitdiff
Unidiff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--rsync/buf.c2
-rw-r--r--rsync/job.c1
2 files changed, 3 insertions, 0 deletions
diff --git a/rsync/buf.c b/rsync/buf.c
index 2814583..c978fff 100644
--- a/rsync/buf.c
+++ b/rsync/buf.c
@@ -3,212 +3,214 @@
3 * librsync -- the library for network deltas 3 * librsync -- the library for network deltas
4 * $Id$ 4 * $Id$
5 * 5 *
6 * Copyright (C) 2000, 2001 by Martin Pool <mbp@samba.org> 6 * Copyright (C) 2000, 2001 by Martin Pool <mbp@samba.org>
7 * 7 *
8 * This program is free software; you can redistribute it and/or 8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License 9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; either version 2.1 of 10 * as published by the Free Software Foundation; either version 2.1 of
11 * the License, or (at your option) any later version. 11 * the License, or (at your option) any later version.
12 * 12 *
13 * This program is distributed in the hope that it will be useful, but 13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of 14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details. 16 * Lesser General Public License for more details.
17 * 17 *
18 * You should have received a copy of the GNU Lesser General Public 18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this program; if not, write to the Free Software 19 * License along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */ 21 */
22 22
23 /* 23 /*
24 | Pick a window, Jimmy, you're leaving. 24 | Pick a window, Jimmy, you're leaving.
25 | -- Martin Schwenke, regularly 25 | -- Martin Schwenke, regularly
26 */ 26 */
27 27
28 28
29/* 29/*
30 * buf.c -- Buffers that map between stdio file streams and librsync 30 * buf.c -- Buffers that map between stdio file streams and librsync
31 * streams. As the stream consumes input and produces output, it is 31 * streams. As the stream consumes input and produces output, it is
32 * refilled from appropriate input and output FILEs. A dynamically 32 * refilled from appropriate input and output FILEs. A dynamically
33 * allocated buffer of configurable size is used as an intermediary. 33 * allocated buffer of configurable size is used as an intermediary.
34 * 34 *
35 * TODO: Perhaps be more efficient by filling the buffer on every call 35 * TODO: Perhaps be more efficient by filling the buffer on every call
36 * even if not yet completely empty. Check that it's really our 36 * even if not yet completely empty. Check that it's really our
37 * buffer, and shuffle remaining data down to the front. 37 * buffer, and shuffle remaining data down to the front.
38 * 38 *
39 * TODO: Perhaps expose a routine for shuffling the buffers. 39 * TODO: Perhaps expose a routine for shuffling the buffers.
40 */ 40 */
41 41
42 42
43#include <config_rsync.h> 43#include <config_rsync.h>
44 44
45#include <assert.h> 45#include <assert.h>
46#include <stdlib.h> 46#include <stdlib.h>
47#include <stdio.h> 47#include <stdio.h>
48#include <errno.h> 48#include <errno.h>
49#include <string.h> 49#include <string.h>
50 50
51#include "rsync.h" 51#include "rsync.h"
52#include "trace.h" 52#include "trace.h"
53#include "buf.h" 53#include "buf.h"
54#include "util.h" 54#include "util.h"
55 55
56/** 56/**
57 * File IO buffer sizes. 57 * File IO buffer sizes.
58 */ 58 */
59int rs_inbuflen = 16000, rs_outbuflen = 16000; 59int rs_inbuflen = 16000, rs_outbuflen = 16000;
60 60
61 61
62struct rs_filebuf { 62struct rs_filebuf {
63 FILE *f; 63 FILE *f;
64 char *buf; 64 char *buf;
65 size_t buf_len; 65 size_t buf_len;
66}; 66};
67 67
68 68
69 69
70rs_filebuf_t *rs_filebuf_new(FILE *f, size_t buf_len) 70rs_filebuf_t *rs_filebuf_new(FILE *f, size_t buf_len)
71{ 71{
72 rs_filebuf_t *pf = rs_alloc_struct(rs_filebuf_t); 72 rs_filebuf_t *pf = rs_alloc_struct(rs_filebuf_t);
73 73
74 pf->buf = rs_alloc(buf_len, "file buffer"); 74 pf->buf = rs_alloc(buf_len, "file buffer");
75 pf->buf_len = buf_len; 75 pf->buf_len = buf_len;
76 pf->f = f; 76 pf->f = f;
77 77
78 return pf; 78 return pf;
79} 79}
80 80
81 81
82void rs_filebuf_free(rs_filebuf_t *fb) 82void rs_filebuf_free(rs_filebuf_t *fb)
83{ 83{
84 if ( fb->buf ) 84 if ( fb->buf )
85 free ( fb->buf ); 85 free ( fb->buf );
86 rs_bzero(fb, sizeof *fb); 86 rs_bzero(fb, sizeof *fb);
87 free(fb); 87 free(fb);
88} 88}
89 89
90 90
91/* 91/*
92 * If the stream has no more data available, read some from F into 92 * If the stream has no more data available, read some from F into
93 * BUF, and let the stream use that. On return, SEEN_EOF is true if 93 * BUF, and let the stream use that. On return, SEEN_EOF is true if
94 * the end of file has passed into the stream. 94 * the end of file has passed into the stream.
95 */ 95 */
96rs_result rs_infilebuf_fill(rs_job_t *job, rs_buffers_t *buf, 96rs_result rs_infilebuf_fill(rs_job_t *job, rs_buffers_t *buf,
97 void *opaque) 97 void *opaque)
98{ 98{
99 job=job;
99 int len; 100 int len;
100 rs_filebuf_t *fb = (rs_filebuf_t *) opaque; 101 rs_filebuf_t *fb = (rs_filebuf_t *) opaque;
101 FILE *f = fb->f; 102 FILE *f = fb->f;
102 103
103 /* This is only allowed if either the buf has no input buffer 104 /* This is only allowed if either the buf has no input buffer
104 * yet, or that buffer could possibly be BUF. */ 105 * yet, or that buffer could possibly be BUF. */
105 if (buf->next_in != NULL) { 106 if (buf->next_in != NULL) {
106 assert(buf->avail_in <= fb->buf_len); 107 assert(buf->avail_in <= fb->buf_len);
107 assert(buf->next_in >= fb->buf); 108 assert(buf->next_in >= fb->buf);
108 assert(buf->next_in <= fb->buf + fb->buf_len); 109 assert(buf->next_in <= fb->buf + fb->buf_len);
109 } else { 110 } else {
110 assert(buf->avail_in == 0); 111 assert(buf->avail_in == 0);
111 } 112 }
112 113
113 if (buf->eof_in || (buf->eof_in = feof(f))) { 114 if (buf->eof_in || (buf->eof_in = feof(f))) {
114 rs_trace("seen end of file on input"); 115 rs_trace("seen end of file on input");
115 buf->eof_in = 1; 116 buf->eof_in = 1;
116 return RS_DONE; 117 return RS_DONE;
117 } 118 }
118 119
119 if (buf->avail_in) 120 if (buf->avail_in)
120 /* Still some data remaining. Perhaps we should read 121 /* Still some data remaining. Perhaps we should read
121 anyhow? */ 122 anyhow? */
122 return RS_DONE; 123 return RS_DONE;
123 124
124 len = fread(fb->buf, 1, fb->buf_len, f); 125 len = fread(fb->buf, 1, fb->buf_len, f);
125 if (len < 0) { 126 if (len < 0) {
126 if (ferror(f)) { 127 if (ferror(f)) {
127 rs_error("error filling buf from file: %s", 128 rs_error("error filling buf from file: %s",
128 strerror(errno)); 129 strerror(errno));
129 return RS_IO_ERROR; 130 return RS_IO_ERROR;
130 } else { 131 } else {
131 rs_error("no error bit, but got %d return when trying to read", 132 rs_error("no error bit, but got %d return when trying to read",
132 len); 133 len);
133 return RS_IO_ERROR; 134 return RS_IO_ERROR;
134 } 135 }
135 } 136 }
136 buf->avail_in = len; 137 buf->avail_in = len;
137 buf->next_in = fb->buf; 138 buf->next_in = fb->buf;
138 139
139 return RS_DONE; 140 return RS_DONE;
140} 141}
141 142
142 143
143/* 144/*
144 * The buf is already using BUF for an output buffer, and probably 145 * The buf is already using BUF for an output buffer, and probably
145 * contains some buffered output now. Write this out to F, and reset 146 * contains some buffered output now. Write this out to F, and reset
146 * the buffer cursor. 147 * the buffer cursor.
147 */ 148 */
148rs_result rs_outfilebuf_drain(rs_job_t *job, rs_buffers_t *buf, void *opaque) 149rs_result rs_outfilebuf_drain(rs_job_t *job, rs_buffers_t *buf, void *opaque)
149{ 150{
151 job=job;
150 int present; 152 int present;
151 rs_filebuf_t *fb = (rs_filebuf_t *) opaque; 153 rs_filebuf_t *fb = (rs_filebuf_t *) opaque;
152 FILE *f = fb->f; 154 FILE *f = fb->f;
153 155
154 /* This is only allowed if either the buf has no output buffer 156 /* This is only allowed if either the buf has no output buffer
155 * yet, or that buffer could possibly be BUF. */ 157 * yet, or that buffer could possibly be BUF. */
156 if (buf->next_out == NULL) { 158 if (buf->next_out == NULL) {
157 assert(buf->avail_out == 0); 159 assert(buf->avail_out == 0);
158 160
159 buf->next_out = fb->buf; 161 buf->next_out = fb->buf;
160 buf->avail_out = fb->buf_len; 162 buf->avail_out = fb->buf_len;
161 163
162 return RS_DONE; 164 return RS_DONE;
163 } 165 }
164 166
165 assert(buf->avail_out <= fb->buf_len); 167 assert(buf->avail_out <= fb->buf_len);
166 assert(buf->next_out >= fb->buf); 168 assert(buf->next_out >= fb->buf);
167 assert(buf->next_out <= fb->buf + fb->buf_len); 169 assert(buf->next_out <= fb->buf + fb->buf_len);
168 170
169 present = buf->next_out - fb->buf; 171 present = buf->next_out - fb->buf;
170 if (present > 0) { 172 if (present > 0) {
171 int result; 173 int result;
172 174
173 assert(present > 0); 175 assert(present > 0);
174 176
175 result = fwrite(fb->buf, 1, present, f); 177 result = fwrite(fb->buf, 1, present, f);
176 if (present != result) { 178 if (present != result) {
177 rs_error("error draining buf to file: %s", 179 rs_error("error draining buf to file: %s",
178 strerror(errno)); 180 strerror(errno));
179 return RS_IO_ERROR; 181 return RS_IO_ERROR;
180 } 182 }
181 183
182 buf->next_out = fb->buf; 184 buf->next_out = fb->buf;
183 buf->avail_out = fb->buf_len; 185 buf->avail_out = fb->buf_len;
184 } 186 }
185 187
186 return RS_DONE; 188 return RS_DONE;
187} 189}
188 190
189 191
190/** 192/**
191 * Default copy implementation that retrieves a part of a stdio file. 193 * Default copy implementation that retrieves a part of a stdio file.
192 */ 194 */
193rs_result rs_file_copy_cb(void *arg, off_t pos, size_t *len, void **buf) 195rs_result rs_file_copy_cb(void *arg, off_t pos, size_t *len, void **buf)
194{ 196{
195 int got; 197 int got;
196 FILE *f = (FILE *) arg; 198 FILE *f = (FILE *) arg;
197 199
198 if (fseek(f, pos, SEEK_SET)) { 200 if (fseek(f, pos, SEEK_SET)) {
199 rs_log(RS_LOG_ERR, "seek failed: %s", strerror(errno)); 201 rs_log(RS_LOG_ERR, "seek failed: %s", strerror(errno));
200 return RS_IO_ERROR; 202 return RS_IO_ERROR;
201 } 203 }
202 204
203 got = fread(*buf, 1, *len, f); 205 got = fread(*buf, 1, *len, f);
204 if (got == -1) { 206 if (got == -1) {
205 rs_error(strerror(errno)); 207 rs_error(strerror(errno));
206 return RS_IO_ERROR; 208 return RS_IO_ERROR;
207 } else if (got == 0) { 209 } else if (got == 0) {
208 rs_error("unexpected eof on fd%d", fileno(f)); 210 rs_error("unexpected eof on fd%d", fileno(f));
209 return RS_INPUT_ENDED; 211 return RS_INPUT_ENDED;
210 } else { 212 } else {
211 *len = got; 213 *len = got;
212 return RS_DONE; 214 return RS_DONE;
213 } 215 }
214} 216}
diff --git a/rsync/job.c b/rsync/job.c
index 680982d..36f39f0 100644
--- a/rsync/job.c
+++ b/rsync/job.c
@@ -1,192 +1,193 @@
1/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*- 1/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
2 * 2 *
3 * librsync -- the library for network deltas 3 * librsync -- the library for network deltas
4 * $Id$ 4 * $Id$
5 * 5 *
6 * Copyright (C) 2000, 2001 by Martin Pool <mbp@samba.org> 6 * Copyright (C) 2000, 2001 by Martin Pool <mbp@samba.org>
7 * 7 *
8 * This program is free software; you can redistribute it and/or 8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License 9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; either version 2.1 of 10 * as published by the Free Software Foundation; either version 2.1 of
11 * the License, or (at your option) any later version. 11 * the License, or (at your option) any later version.
12 * 12 *
13 * This program is distributed in the hope that it will be useful, but 13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of 14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details. 16 * Lesser General Public License for more details.
17 * 17 *
18 * You should have received a copy of the GNU Lesser General Public 18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this program; if not, write to the Free Software 19 * License along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */ 21 */
22 22
23 23
24 /* 24 /*
25 | The hard, lifeless I covered up the 25 | The hard, lifeless I covered up the
26 | warm, pulsing It; protecting and 26 | warm, pulsing It; protecting and
27 | sheltering. 27 | sheltering.
28 */ 28 */
29 29
30/* 30/*
31 * job.c -- Generic state-machine interface. The point of this is 31 * job.c -- Generic state-machine interface. The point of this is
32 * that we need to be able to suspend and resume processing at any 32 * that we need to be able to suspend and resume processing at any
33 * point at which the buffers may block. We could do that using 33 * point at which the buffers may block. We could do that using
34 * setjmp or similar tricks, but this is probably simpler. 34 * setjmp or similar tricks, but this is probably simpler.
35 * 35 *
36 * TODO: We have a few functions to do with reading a netint, stashing 36 * TODO: We have a few functions to do with reading a netint, stashing
37 * it somewhere, then moving into a different state. Is it worth 37 * it somewhere, then moving into a different state. Is it worth
38 * writing generic functions fo r that, or would it be too confusing? 38 * writing generic functions fo r that, or would it be too confusing?
39 */ 39 */
40 40
41 41
42#include <config_rsync.h> 42#include <config_rsync.h>
43 43
44#include <stdlib.h> 44#include <stdlib.h>
45#include <assert.h> 45#include <assert.h>
46#include <stdio.h> 46#include <stdio.h>
47 47
48#include "rsync.h" 48#include "rsync.h"
49#include "stream.h" 49#include "stream.h"
50#include "util.h" 50#include "util.h"
51#include "sumset.h" 51#include "sumset.h"
52#include "job.h" 52#include "job.h"
53#include "trace.h" 53#include "trace.h"
54 54
55 55
56static const int rs_job_tag = 20010225; 56static const int rs_job_tag = 20010225;
57 57
58static rs_result rs_job_work(rs_job_t *job, rs_buffers_t *buffers); 58static rs_result rs_job_work(rs_job_t *job, rs_buffers_t *buffers);
59 59
60 60
61rs_job_t * rs_job_new(char const *job_name, rs_result (*statefn)(rs_job_t *)) 61rs_job_t * rs_job_new(char const *job_name, rs_result (*statefn)(rs_job_t *))
62{ 62{
63 rs_job_t *job; 63 rs_job_t *job;
64 64
65 job = rs_alloc_struct(rs_job_t); 65 job = rs_alloc_struct(rs_job_t);
66 66
67 job->job_name = job_name; 67 job->job_name = job_name;
68 job->dogtag = rs_job_tag; 68 job->dogtag = rs_job_tag;
69 job->statefn = statefn; 69 job->statefn = statefn;
70 70
71 job->stats.op = job_name; 71 job->stats.op = job_name;
72 72
73 rs_trace("start %s job", job_name); 73 rs_trace("start %s job", job_name);
74 74
75 return job; 75 return job;
76} 76}
77 77
78 78
79void rs_job_check(rs_job_t *job) 79void rs_job_check(rs_job_t *job)
80{ 80{
81 assert(job->dogtag == rs_job_tag); 81 assert(job->dogtag == rs_job_tag);
82} 82}
83 83
84 84
85rs_result rs_job_free(rs_job_t *job) 85rs_result rs_job_free(rs_job_t *job)
86{ 86{
87 rs_bzero(job, sizeof *job); 87 rs_bzero(job, sizeof *job);
88 free(job); 88 free(job);
89 89
90 return RS_DONE; 90 return RS_DONE;
91} 91}
92 92
93 93
94 94
95static rs_result rs_job_s_complete(rs_job_t *job) 95static rs_result rs_job_s_complete(rs_job_t *job)
96{ 96{
97 job = job;
97 rs_fatal("should not be reached"); 98 rs_fatal("should not be reached");
98 return RS_INTERNAL_ERROR; 99 return RS_INTERNAL_ERROR;
99} 100}
100 101
101 102
102static rs_result rs_job_complete(rs_job_t *job, rs_result result) 103static rs_result rs_job_complete(rs_job_t *job, rs_result result)
103{ 104{
104 rs_job_check(job); 105 rs_job_check(job);
105 106
106 job->statefn = rs_job_s_complete; 107 job->statefn = rs_job_s_complete;
107 job->final_result = result; 108 job->final_result = result;
108 109
109 if (result != RS_DONE) { 110 if (result != RS_DONE) {
110 rs_error("%s job failed: %s", job->job_name, rs_strerror(result)); 111 rs_error("%s job failed: %s", job->job_name, rs_strerror(result));
111 } else { 112 } else {
112 rs_trace("%s job complete", job->job_name); 113 rs_trace("%s job complete", job->job_name);
113 } 114 }
114 115
115 if (result == RS_DONE && !rs_tube_is_idle(job)) 116 if (result == RS_DONE && !rs_tube_is_idle(job))
116 /* Processing is finished, but there is still some data 117 /* Processing is finished, but there is still some data
117 * waiting to get into the output buffer. */ 118 * waiting to get into the output buffer. */
118 return RS_BLOCKED; 119 return RS_BLOCKED;
119 else 120 else
120 return result; 121 return result;
121} 122}
122 123
123 124
124/** 125/**
125 * \brief Run a ::rs_job_t state machine until it blocks 126 * \brief Run a ::rs_job_t state machine until it blocks
126 * (::RS_BLOCKED), returns an error, or completes (::RS_COMPLETE). 127 * (::RS_BLOCKED), returns an error, or completes (::RS_COMPLETE).
127 * 128 *
128 * \return The ::rs_result that caused iteration to stop. 129 * \return The ::rs_result that caused iteration to stop.
129 * 130 *
130 * \param ending True if there is no more data after what's in the 131 * \param ending True if there is no more data after what's in the
131 * input buffer. The final block checksum will run across whatever's 132 * input buffer. The final block checksum will run across whatever's
132 * in there, without trying to accumulate anything else. 133 * in there, without trying to accumulate anything else.
133 */ 134 */
134rs_result rs_job_iter(rs_job_t *job, rs_buffers_t *buffers) 135rs_result rs_job_iter(rs_job_t *job, rs_buffers_t *buffers)
135{ 136{
136 rs_result result; 137 rs_result result;
137 rs_long_t orig_in, orig_out; 138 rs_long_t orig_in, orig_out;
138 139
139 orig_in = buffers->avail_in; 140 orig_in = buffers->avail_in;
140 orig_out = buffers->avail_out; 141 orig_out = buffers->avail_out;
141 142
142 result = rs_job_work(job, buffers); 143 result = rs_job_work(job, buffers);
143 144
144 if (result == RS_BLOCKED || result == RS_DONE) 145 if (result == RS_BLOCKED || result == RS_DONE)
145 if ((orig_in == buffers->avail_in) && (orig_out == buffers->avail_out) 146 if ((orig_in == buffers->avail_in) && (orig_out == buffers->avail_out)
146 && orig_in && orig_out) { 147 && orig_in && orig_out) {
147 rs_log(RS_LOG_ERR, "internal error: job made no progress " 148 rs_log(RS_LOG_ERR, "internal error: job made no progress "
148 "[orig_in=%.0f, orig_out=%.0f, final_in=%.0f, final_out=%.0f]", 149 "[orig_in=%.0f, orig_out=%.0f, final_in=%.0f, final_out=%.0f]",
149 (double) orig_in, (double) orig_out, (double) buffers->avail_in, 150 (double) orig_in, (double) orig_out, (double) buffers->avail_in,
150 (double) buffers->avail_out); 151 (double) buffers->avail_out);
151 return RS_INTERNAL_ERROR; 152 return RS_INTERNAL_ERROR;
152 } 153 }
153 154
154 return result; 155 return result;
155} 156}
156 157
157 158
158static rs_result 159static rs_result
159rs_job_work(rs_job_t *job, rs_buffers_t *buffers) 160rs_job_work(rs_job_t *job, rs_buffers_t *buffers)
160{ 161{
161 rs_result result; 162 rs_result result;
162 163
163 rs_job_check(job); 164 rs_job_check(job);
164 165
165 if (!buffers) { 166 if (!buffers) {
166 rs_error("NULL buffer passed to rs_job_iter"); 167 rs_error("NULL buffer passed to rs_job_iter");
167 return RS_PARAM_ERROR; 168 return RS_PARAM_ERROR;
168 } 169 }
169 job->stream = buffers; 170 job->stream = buffers;
170 171
171 while (1) { 172 while (1) {
172 result = rs_tube_catchup(job); 173 result = rs_tube_catchup(job);
173 if (result == RS_BLOCKED) 174 if (result == RS_BLOCKED)
174 return result; 175 return result;
175 else if (result != RS_DONE) 176 else if (result != RS_DONE)
176 return rs_job_complete(job, result); 177 return rs_job_complete(job, result);
177 178
178 if (job->statefn == rs_job_s_complete) { 179 if (job->statefn == rs_job_s_complete) {
179 if (rs_tube_is_idle(job)) 180 if (rs_tube_is_idle(job))
180 return RS_DONE; 181 return RS_DONE;
181 else 182 else
182 return RS_BLOCKED; 183 return RS_BLOCKED;
183 } else { 184 } else {
184 result = job->statefn(job); 185 result = job->statefn(job);
185 if (result == RS_RUNNING) 186 if (result == RS_RUNNING)
186 continue; 187 continue;
187 else if (result == RS_BLOCKED) 188 else if (result == RS_BLOCKED)
188 return result; 189 return result;
189 else 190 else
190 return rs_job_complete(job, result); 191 return rs_job_complete(job, result);
191 } 192 }
192 } 193 }