~ubuntu-branches/debian/sid/subversion/sid

« back to all changes in this revision

Viewing changes to subversion/bindings/javahl/src/org/apache/subversion/javahl/remote/StatusEditor.java

  • Committer: Package Import Robot
  • Author(s): James McCoy
  • Date: 2015-08-07 21:32:47 UTC
  • mfrom: (0.2.15) (4.1.7 experimental)
  • Revision ID: package-import@ubuntu.com-20150807213247-ozyewtmgsr6tkewl
Tags: 1.9.0-1
* Upload to unstable
* New upstream release.
  + Security fixes
    - CVE-2015-3184: Mixed anonymous/authenticated path-based authz with
      httpd 2.4
    - CVE-2015-3187: svn_repos_trace_node_locations() reveals paths hidden
      by authz
* Add >= 2.7 requirement for python-all-dev Build-Depends, needed to run
  tests.
* Remove Build-Conflicts against ruby-test-unit.  (Closes: #791844)
* Remove patches/apache_module_dependency in favor of expressing the
  dependencies in authz_svn.load/dav_svn.load.
* Build-Depend on apache2-dev (>= 2.4.16) to ensure ap_some_authn_required()
  is available when building mod_authz_svn and Depend on apache2-bin (>=
  2.4.16) for runtime support.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
 * @copyright
 
3
 * ====================================================================
 
4
 *    Licensed to the Apache Software Foundation (ASF) under one
 
5
 *    or more contributor license agreements.  See the NOTICE file
 
6
 *    distributed with this work for additional information
 
7
 *    regarding copyright ownership.  The ASF licenses this file
 
8
 *    to you under the Apache License, Version 2.0 (the
 
9
 *    "License"); you may not use this file except in compliance
 
10
 *    with the License.  You may obtain a copy of the License at
 
11
 *
 
12
 *      http://www.apache.org/licenses/LICENSE-2.0
 
13
 *
 
14
 *    Unless required by applicable law or agreed to in writing,
 
15
 *    software distributed under the License is distributed on an
 
16
 *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 
17
 *    KIND, either express or implied.  See the License for the
 
18
 *    specific language governing permissions and limitations
 
19
 *    under the License.
 
20
 * ====================================================================
 
21
 * @endcopyright
 
22
 */
 
23
 
 
24
package org.apache.subversion.javahl.remote;
 
25
 
 
26
import org.apache.subversion.javahl.types.*;
 
27
import org.apache.subversion.javahl.callback.*;
 
28
 
 
29
import org.apache.subversion.javahl.ISVNEditor;
 
30
 
 
31
import java.util.Map;
 
32
import java.util.GregorianCalendar;
 
33
import java.util.Locale;
 
34
import java.util.SimpleTimeZone;
 
35
import java.io.InputStream;
 
36
import java.io.IOException;
 
37
import java.nio.charset.Charset;
 
38
 
 
39
/**
 
40
 * Package-private editor implementation that converts an editor drive
 
41
 * to {@link RemoteStatus} callbacks.
 
42
 * @since 1.9
 
43
 */
 
44
class StatusEditor implements ISVNEditor
 
45
{
 
46
    StatusEditor(RemoteStatus receiver)
 
47
    {
 
48
        this.receiver = receiver;
 
49
    }
 
50
    protected RemoteStatus receiver = null;
 
51
 
 
52
    protected void checkState()
 
53
    {
 
54
        if (receiver == null)
 
55
            throw new IllegalStateException("Status editor is not active");
 
56
    }
 
57
 
 
58
    public void dispose()
 
59
    {
 
60
        //DEBUG:System.err.println("  [J] StatusEditor.dispose");
 
61
        if (this.receiver != null)
 
62
            abort();
 
63
    }
 
64
 
 
65
    public void addDirectory(String relativePath,
 
66
                             Iterable<String> children,
 
67
                             Map<String, byte[]> properties,
 
68
                             long replacesRevision)
 
69
    {
 
70
        //DEBUG:System.err.println("  [J] StatusEditor.addDirectory");
 
71
        checkState();
 
72
        receiver.addedDirectory(relativePath);
 
73
    }
 
74
 
 
75
    public void addFile(String relativePath,
 
76
                        Checksum checksum,
 
77
                        InputStream contents,
 
78
                        Map<String, byte[]> properties,
 
79
                        long replacesRevision)
 
80
    {
 
81
        //DEBUG:System.err.println("  [J] StatusEditor.addFile");
 
82
        if (contents != null) {
 
83
            try {
 
84
                contents.close();
 
85
            } catch (IOException ex) {
 
86
                throw new RuntimeException(ex);
 
87
            }
 
88
        }
 
89
 
 
90
        checkState();
 
91
        receiver.addedFile(relativePath);
 
92
    }
 
93
 
 
94
    public void addSymlink(String relativePath,
 
95
                           String target,
 
96
                           Map<String, byte[]> properties,
 
97
                           long replacesRevision)
 
98
    {
 
99
        //DEBUG:System.err.println("  [J] StatusEditor.addSymlink");
 
100
        checkState();
 
101
        receiver.addedSymlink(relativePath);
 
102
    }
 
103
 
 
104
    public void addAbsent(String relativePath,
 
105
                          NodeKind kind,
 
106
                          long replacesRevision)
 
107
    {
 
108
        //DEBUG:System.err.println("  [J] StatusEditor.addAbsent");
 
109
        checkState();
 
110
        throw new RuntimeException("Not implemented: StatusEditor.addAbsent");
 
111
    }
 
112
 
 
113
    public void alterDirectory(String relativePath,
 
114
                               long revision,
 
115
                               Iterable<String> children,
 
116
                               Map<String, byte[]> properties)
 
117
    {
 
118
        //DEBUG:System.err.println("  [J] StatusEditor.alterDirectory");
 
119
        checkState();
 
120
        receiver.modifiedDirectory(relativePath, (children != null),
 
121
                                   props_changed(properties),
 
122
                                   make_entry(properties));
 
123
    }
 
124
 
 
125
    public void alterFile(String relativePath,
 
126
                          long revision,
 
127
                          Checksum checksum,
 
128
                          InputStream contents,
 
129
                          Map<String, byte[]> properties)
 
130
    {
 
131
        //DEBUG:System.err.println("  [J] StatusEditor.alterFile");
 
132
        if (contents != null) {
 
133
            try {
 
134
                contents.close();
 
135
            } catch (IOException ex) {
 
136
                throw new RuntimeException(ex);
 
137
            }
 
138
        }
 
139
 
 
140
        checkState();
 
141
        receiver.modifiedFile(relativePath,
 
142
                              (checksum != null && contents != null),
 
143
                              props_changed(properties),
 
144
                              make_entry(properties));
 
145
    }
 
146
 
 
147
    public void alterSymlink(String relativePath,
 
148
                             long revision,
 
149
                             String target,
 
150
                             Map<String, byte[]> properties)
 
151
    {
 
152
        //DEBUG:System.err.println("  [J] StatusEditor.alterSymlink");
 
153
        checkState();
 
154
        receiver.modifiedSymlink(relativePath, (target != null),
 
155
                                 props_changed(properties),
 
156
                                 make_entry(properties));
 
157
    }
 
158
 
 
159
    public void delete(String relativePath, long revision)
 
160
    {
 
161
        //DEBUG:System.err.println("  [J] StatusEditor.delete");
 
162
        checkState();
 
163
        receiver.deleted(relativePath);
 
164
    }
 
165
 
 
166
    public void copy(String sourceRelativePath,
 
167
                     long sourceRevision,
 
168
                     String destinationRelativePath,
 
169
                     long replacesRevision)
 
170
    {
 
171
        //DEBUG:System.err.println("  [J] StatusEditor.copy");
 
172
        checkState();
 
173
        throw new RuntimeException("Not implemented: StatusEditor.copy");
 
174
    }
 
175
 
 
176
    public void move(String sourceRelativePath,
 
177
                     long sourceRevision,
 
178
                     String destinationRelativePath,
 
179
                     long replacesRevision)
 
180
    {
 
181
        //DEBUG:System.err.println("  [J] StatusEditor.move");
 
182
        checkState();
 
183
        throw new RuntimeException("Not implemented: StatusEditor.move");
 
184
    }
 
185
 
 
186
    public void complete()
 
187
    {
 
188
        //DEBUG:System.err.println("  [J] StatusEditor.complete");
 
189
        abort();
 
190
    }
 
191
 
 
192
    public void abort()
 
193
    {
 
194
        //DEBUG:System.err.println("  [J] StatusEditor.abort");
 
195
        checkState();
 
196
        receiver = null;
 
197
    }
 
198
 
 
199
    /*
 
200
     * Construct a RemoteStatus.Entry record from the given properties.
 
201
     */
 
202
    private static final Charset UTF8 = Charset.forName("UTF-8");
 
203
    private static final SimpleTimeZone UTC =
 
204
        new SimpleTimeZone(SimpleTimeZone.UTC_TIME, "UTC");
 
205
    private static final String entryprop_uuid = "svn:entry:uuid";
 
206
    private static final String entryprop_author = "svn:entry:last-author";
 
207
    private static final String entryprop_revision = "svn:entry:committed-rev";
 
208
    private static final String entryprop_timestamp = "svn:entry:committed-date";
 
209
    private final GregorianCalendar entry_calendar =
 
210
        new GregorianCalendar(UTC, Locale.ROOT);
 
211
 
 
212
    // FIXME: Room for improvement here. There are likely to be a lot
 
213
    // of duplicate entries and we should be able to avoid parsing the
 
214
    // duplicates all over again. Need a map <raw data> -> Entry to
 
215
    // just look up the entries instead of parsing them.
 
216
    private final RemoteStatus.Entry make_entry(Map<String, byte[]> properties)
 
217
    {
 
218
        final byte[] raw_uuid = properties.get(entryprop_uuid);
 
219
        final byte[] raw_author = properties.get(entryprop_author);
 
220
        final byte[] raw_revision = properties.get(entryprop_revision);
 
221
        final byte[] raw_timestamp = properties.get(entryprop_timestamp);
 
222
 
 
223
        long parsed_timestamp = -1;
 
224
        if (raw_timestamp != null)
 
225
        {
 
226
            // Parse: 2013-07-04T23:17:59.128366Z
 
227
            final String isodate = new String(raw_timestamp, UTF8);
 
228
 
 
229
            final int year = Integer.valueOf(isodate.substring(0,4), 10);
 
230
            final int month = Integer.valueOf(isodate.substring(5,7), 10);
 
231
            final int day = Integer.valueOf(isodate.substring(8,10), 10);
 
232
            final int hour = Integer.valueOf(isodate.substring(11,13), 10);
 
233
            final int minute = Integer.valueOf(isodate.substring(14,16), 10);
 
234
            final int second = Integer.valueOf(isodate.substring(17,19), 10);
 
235
            final int micro = Integer.valueOf(isodate.substring(20,26), 10);
 
236
            entry_calendar.set(year, month, day, hour, minute, second);
 
237
 
 
238
             // Use integer rounding to add milliseconds
 
239
            parsed_timestamp =
 
240
                (1000 * entry_calendar.getTimeInMillis() + micro + 500) / 1000;
 
241
        }
 
242
 
 
243
        return new RemoteStatus.Entry(
 
244
            (raw_uuid == null ? null : new String(raw_uuid, UTF8)),
 
245
            (raw_author == null ? null : new String(raw_author, UTF8)),
 
246
            (raw_revision == null ? Revision.SVN_INVALID_REVNUM
 
247
             : Long.valueOf(new String(raw_revision, UTF8), 10)),
 
248
            parsed_timestamp);
 
249
    }
 
250
 
 
251
    /*
 
252
     * Filter entry props from the incoming properties
 
253
     */
 
254
    private static final String wcprop_prefix = "svn:wc:";
 
255
    private static final String entryprop_prefix = "svn:entry:";
 
256
    private static final boolean props_changed(Map<String, byte[]> properties)
 
257
    {
 
258
        if (properties != null)
 
259
            for (String name : properties.keySet())
 
260
                if (!name.startsWith(wcprop_prefix)
 
261
                    && !name.startsWith(entryprop_prefix))
 
262
                    return true;
 
263
        return false;
 
264
    }
 
265
}