2
This code is derived from jgit (http://eclipse.org/jgit).
3
Copyright owners are documented in jgit's IP log.
5
This program and the accompanying materials are made available
6
under the terms of the Eclipse Distribution License v1.0 which
7
accompanies this distribution, is reproduced below, and is
8
available at http://www.eclipse.org/org/documents/edl-v10.php
12
Redistribution and use in source and binary forms, with or
13
without modification, are permitted provided that the following
16
- Redistributions of source code must retain the above copyright
17
notice, this list of conditions and the following disclaimer.
19
- Redistributions in binary form must reproduce the above
20
copyright notice, this list of conditions and the following
21
disclaimer in the documentation and/or other materials provided
22
with the distribution.
24
- Neither the name of the Eclipse Foundation, Inc. nor the
25
names of its contributors may be used to endorse or promote
26
products derived from this software without specific prior
29
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
30
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
31
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
32
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
34
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
35
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
36
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
38
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
41
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
45
using System.Collections.Generic;
51
using NGit.Storage.File;
56
namespace NGit.Transport
58
/// <summary>Implements the server side of a push connection, receiving objects.</summary>
59
/// <remarks>Implements the server side of a push connection, receiving objects.</remarks>
60
public class ReceivePack
62
/// <summary>Database we write the stored objects into.</summary>
63
/// <remarks>Database we write the stored objects into.</remarks>
64
private readonly Repository db;
67
/// Revision traversal support over
68
/// <see cref="db">db</see>
71
private readonly RevWalk walk;
74
/// Is the client connection a bi-directional socket or pipe?
76
/// If true, this class assumes it can perform multiple read and write cycles
77
/// with the client over the input and output streams.
80
/// Is the client connection a bi-directional socket or pipe?
82
/// If true, this class assumes it can perform multiple read and write cycles
83
/// with the client over the input and output streams. This matches the
84
/// functionality available with a standard TCP/IP connection, or a local
85
/// operating system or in-memory pipe.
87
/// If false, this class runs in a read everything then output results mode,
88
/// making it suitable for single round-trip systems RPCs such as HTTP.
90
private bool biDirectionalPipe = true;
92
/// <summary>Should an incoming transfer validate objects?</summary>
93
private bool checkReceivedObjects;
95
/// <summary>Should an incoming transfer permit create requests?</summary>
96
private bool allowCreates;
98
/// <summary>Should an incoming transfer permit delete requests?</summary>
99
private bool allowDeletes;
101
/// <summary>Should an incoming transfer permit non-fast-forward requests?</summary>
102
private bool allowNonFastForwards;
104
private bool allowOfsDelta;
106
/// <summary>Identity to record action as within the reflog.</summary>
107
/// <remarks>Identity to record action as within the reflog.</remarks>
108
private PersonIdent refLogIdent;
110
/// <summary>Filter used while advertising the refs to the client.</summary>
111
/// <remarks>Filter used while advertising the refs to the client.</remarks>
112
private RefFilter refFilter;
114
/// <summary>Hook to validate the update commands before execution.</summary>
115
/// <remarks>Hook to validate the update commands before execution.</remarks>
116
private PreReceiveHook preReceive;
118
/// <summary>Hook to report on the commands after execution.</summary>
119
/// <remarks>Hook to report on the commands after execution.</remarks>
120
private PostReceiveHook postReceive;
122
/// <summary>Timeout in seconds to wait for client interaction.</summary>
123
/// <remarks>Timeout in seconds to wait for client interaction.</remarks>
128
/// <see cref="timeout">timeout</see>
131
private InterruptTimer timer;
133
private TimeoutInputStream timeoutIn;
135
private InputStream rawIn;
137
private OutputStream rawOut;
139
private OutputStream msgOut;
141
private PacketLineIn pckIn;
143
private PacketLineOut pckOut;
145
private PackParser parser;
147
/// <summary>The refs we advertised as existing at the start of the connection.</summary>
148
/// <remarks>The refs we advertised as existing at the start of the connection.</remarks>
149
private IDictionary<string, Ref> refs;
151
/// <summary>All SHA-1s shown to the client, which can be possible edges.</summary>
152
/// <remarks>All SHA-1s shown to the client, which can be possible edges.</remarks>
153
private ICollection<ObjectId> advertisedHaves;
155
/// <summary>Capabilities requested by the client.</summary>
156
/// <remarks>Capabilities requested by the client.</remarks>
157
private ICollection<string> enabledCapablities;
159
/// <summary>Commands to execute, as received by the client.</summary>
160
/// <remarks>Commands to execute, as received by the client.</remarks>
161
private IList<ReceiveCommand> commands;
163
/// <summary>Error to display instead of advertising the references.</summary>
164
/// <remarks>Error to display instead of advertising the references.</remarks>
165
private StringBuilder advertiseError;
167
/// <summary>An exception caught while unpacking and fsck'ing the objects.</summary>
168
/// <remarks>An exception caught while unpacking and fsck'ing the objects.</remarks>
169
private Exception unpackError;
173
/// <see cref="BasePackPushConnection.CAPABILITY_REPORT_STATUS">BasePackPushConnection.CAPABILITY_REPORT_STATUS
177
private bool reportStatus;
181
/// <see cref="BasePackPushConnection.CAPABILITY_SIDE_BAND_64K">BasePackPushConnection.CAPABILITY_SIDE_BAND_64K
185
private bool sideBand;
187
/// <summary>Lock around the received pack file, while updating refs.</summary>
188
/// <remarks>Lock around the received pack file, while updating refs.</remarks>
189
private PackLock packLock;
191
private bool checkReferencedIsReachable;
193
/// <summary>Create a new pack receive for an open repository.</summary>
194
/// <remarks>Create a new pack receive for an open repository.</remarks>
195
/// <param name="into">the destination repository.</param>
196
public ReceivePack(Repository into)
199
walk = new RevWalk(db);
200
ReceivePack.ReceiveConfig cfg = db.GetConfig().Get(ReceivePack.ReceiveConfig.KEY);
201
checkReceivedObjects = cfg.checkReceivedObjects;
202
allowCreates = cfg.allowCreates;
203
allowDeletes = cfg.allowDeletes;
204
allowNonFastForwards = cfg.allowNonFastForwards;
205
allowOfsDelta = cfg.allowOfsDelta;
206
refFilter = RefFilter.DEFAULT;
207
preReceive = PreReceiveHook.NULL;
208
postReceive = PostReceiveHook.NULL;
209
advertisedHaves = new HashSet<ObjectId>();
212
private class ReceiveConfig
214
private sealed class _SectionParser_218 : Config.SectionParser<ReceivePack.ReceiveConfig
217
public _SectionParser_218()
221
public ReceivePack.ReceiveConfig Parse(Config cfg)
223
return new ReceivePack.ReceiveConfig(cfg);
227
internal static readonly Config.SectionParser<ReceivePack.ReceiveConfig> KEY = new
228
_SectionParser_218();
230
internal readonly bool checkReceivedObjects;
232
internal readonly bool allowCreates;
234
internal readonly bool allowDeletes;
236
internal readonly bool allowNonFastForwards;
238
internal readonly bool allowOfsDelta;
240
internal ReceiveConfig(Config config)
242
checkReceivedObjects = config.GetBoolean("receive", "fsckobjects", false);
244
allowDeletes = !config.GetBoolean("receive", "denydeletes", false);
245
allowNonFastForwards = !config.GetBoolean("receive", "denynonfastforwards", false
247
allowOfsDelta = config.GetBoolean("repack", "usedeltabaseoffset", true);
251
/// <returns>the repository this receive completes into.</returns>
252
public Repository GetRepository()
257
/// <returns>the RevWalk instance used by this connection.</returns>
258
public RevWalk GetRevWalk()
263
/// <returns>all refs which were advertised to the client.</returns>
264
public IDictionary<string, Ref> GetAdvertisedRefs()
268
refs = refFilter.Filter(db.GetAllRefs());
269
Ref head = refs.Get(Constants.HEAD);
270
if (head != null && head.IsSymbolic())
272
Sharpen.Collections.Remove(refs, Constants.HEAD);
274
foreach (Ref @ref in refs.Values)
276
if (@ref.GetObjectId() != null)
278
advertisedHaves.AddItem(@ref.GetObjectId());
281
Sharpen.Collections.AddAll(advertisedHaves, db.GetAdditionalHaves());
286
/// <returns>the set of objects advertised as present in this repository.</returns>
287
public ICollection<ObjectId> GetAdvertisedObjects()
290
return advertisedHaves;
294
/// true if this instance will validate all referenced, but not
295
/// supplied by the client, objects are reachable from another
298
public virtual bool IsCheckReferencedObjectsAreReachable()
300
return checkReferencedIsReachable;
303
/// <summary>Validate all referenced but not supplied objects are reachable.</summary>
305
/// Validate all referenced but not supplied objects are reachable.
307
/// If enabled, this instance will verify that references to objects not
308
/// contained within the received pack are already reachable through at least
309
/// one other reference selected by the
310
/// <see cref="GetRefFilter()">GetRefFilter()</see>
313
/// <see cref="GetAdvertisedRefs()">GetAdvertisedRefs()</see>
316
/// This feature is useful when the application doesn't trust the client to
317
/// not provide a forged SHA-1 reference to an object, in an attempt to
318
/// access parts of the DAG that they aren't allowed to see and which have
319
/// been hidden from them via the configured
320
/// <see cref="RefFilter">RefFilter</see>
323
/// Enabling this feature may imply at least some, if not all, of the same
324
/// functionality performed by
325
/// <see cref="SetCheckReceivedObjects(bool)">SetCheckReceivedObjects(bool)</see>
327
/// Applications are encouraged to enable both features, if desired.
330
/// <code>true</code>
331
/// to enable the additional check.
333
public virtual void SetCheckReferencedObjectsAreReachable(bool b)
335
this.checkReferencedIsReachable = b;
339
/// true if this class expects a bi-directional pipe opened between
340
/// the client and itself. The default is true.
342
public virtual bool IsBiDirectionalPipe()
344
return biDirectionalPipe;
347
/// <param name="twoWay">
348
/// if true, this class will assume the socket is a fully
349
/// bidirectional pipe between the two peers and takes advantage
350
/// of that by first transmitting the known refs, then waiting to
351
/// read commands. If false, this class assumes it must read the
352
/// commands before writing output and does not perform the
353
/// initial advertising.
355
public virtual void SetBiDirectionalPipe(bool twoWay)
357
biDirectionalPipe = twoWay;
361
/// true if this instance will verify received objects are formatted
362
/// correctly. Validating objects requires more CPU time on this side
363
/// of the connection.
365
public virtual bool IsCheckReceivedObjects()
367
return checkReceivedObjects;
370
/// <param name="check">
371
/// true to enable checking received objects; false to assume all
372
/// received objects are valid.
374
public virtual void SetCheckReceivedObjects(bool check)
376
checkReceivedObjects = check;
379
/// <returns>true if the client can request refs to be created.</returns>
380
public virtual bool IsAllowCreates()
385
/// <param name="canCreate">true to permit create ref commands to be processed.</param>
386
public virtual void SetAllowCreates(bool canCreate)
388
allowCreates = canCreate;
391
/// <returns>true if the client can request refs to be deleted.</returns>
392
public virtual bool IsAllowDeletes()
397
/// <param name="canDelete">true to permit delete ref commands to be processed.</param>
398
public virtual void SetAllowDeletes(bool canDelete)
400
allowDeletes = canDelete;
404
/// true if the client can request non-fast-forward updates of a ref,
405
/// possibly making objects unreachable.
407
public virtual bool IsAllowNonFastForwards()
409
return allowNonFastForwards;
412
/// <param name="canRewind">
413
/// true to permit the client to ask for non-fast-forward updates
414
/// of an existing ref.
416
public virtual void SetAllowNonFastForwards(bool canRewind)
418
allowNonFastForwards = canRewind;
421
/// <returns>identity of the user making the changes in the reflog.</returns>
422
public virtual PersonIdent GetRefLogIdent()
427
/// <summary>Set the identity of the user appearing in the affected reflogs.</summary>
429
/// Set the identity of the user appearing in the affected reflogs.
431
/// The timestamp portion of the identity is ignored. A new identity with the
432
/// current timestamp will be created automatically when the updates occur
433
/// and the log records are written.
435
/// <param name="pi">
436
/// identity of the user. If null the identity will be
437
/// automatically determined based on the repository
440
public virtual void SetRefLogIdent(PersonIdent pi)
445
/// <returns>the filter used while advertising the refs to the client</returns>
446
public virtual RefFilter GetRefFilter()
451
/// <summary>Set the filter used while advertising the refs to the client.</summary>
453
/// Set the filter used while advertising the refs to the client.
455
/// Only refs allowed by this filter will be shown to the client.
456
/// Clients may still attempt to create or update a reference hidden
457
/// by the configured
458
/// <see cref="RefFilter">RefFilter</see>
459
/// . These attempts should be
460
/// rejected by a matching
461
/// <see cref="PreReceiveHook">PreReceiveHook</see>
464
/// <param name="refFilter">the filter; may be null to show all refs.</param>
465
public virtual void SetRefFilter(RefFilter refFilter)
467
this.refFilter = refFilter != null ? refFilter : RefFilter.DEFAULT;
470
/// <returns>get the hook invoked before updates occur.</returns>
471
public virtual PreReceiveHook GetPreReceiveHook()
476
/// <summary>Set the hook which is invoked prior to commands being executed.</summary>
478
/// Set the hook which is invoked prior to commands being executed.
480
/// Only valid commands (those which have no obvious errors according to the
481
/// received input and this instance's configuration) are passed into the
482
/// hook. The hook may mark a command with a result of any value other than
483
/// <see cref="Result.NOT_ATTEMPTED">Result.NOT_ATTEMPTED</see>
484
/// to block its execution.
486
/// The hook may be called with an empty command collection if the current
487
/// set is completely invalid.
489
/// <param name="h">the hook instance; may be null to disable the hook.</param>
490
public virtual void SetPreReceiveHook(PreReceiveHook h)
492
preReceive = h != null ? h : PreReceiveHook.NULL;
495
/// <returns>get the hook invoked after updates occur.</returns>
496
public virtual PostReceiveHook GetPostReceiveHook()
501
/// <summary>Set the hook which is invoked after commands are executed.</summary>
503
/// Set the hook which is invoked after commands are executed.
505
/// Only successful commands (type is
506
/// <see cref="Result.OK">Result.OK</see>
507
/// ) are passed into the
508
/// hook. The hook may be called with an empty command collection if the
509
/// current set all resulted in an error.
511
/// <param name="h">the hook instance; may be null to disable the hook.</param>
512
public virtual void SetPostReceiveHook(PostReceiveHook h)
514
postReceive = h != null ? h : PostReceiveHook.NULL;
517
/// <returns>timeout (in seconds) before aborting an IO operation.</returns>
518
public virtual int GetTimeout()
523
/// <summary>Set the timeout before willing to abort an IO call.</summary>
524
/// <remarks>Set the timeout before willing to abort an IO call.</remarks>
525
/// <param name="seconds">
526
/// number of seconds to wait (with no data transfer occurring)
527
/// before aborting an IO read or write operation with the
528
/// connected client.
530
public virtual void SetTimeout(int seconds)
535
/// <returns>all of the command received by the current request.</returns>
536
public virtual IList<ReceiveCommand> GetAllCommands()
538
return Sharpen.Collections.UnmodifiableList(commands);
541
/// <summary>Send an error message to the client.</summary>
543
/// Send an error message to the client.
545
/// If any error messages are sent before the references are advertised to
546
/// the client, the errors will be sent instead of the advertisement and the
547
/// receive operation will be aborted. All clients should receive and display
548
/// such early stage errors.
550
/// If the reference advertisements have already been sent, messages are sent
551
/// in a side channel. If the client doesn't support receiving messages, the
552
/// message will be discarded, with no other indication to the caller or to
555
/// <see cref="PreReceiveHook">PreReceiveHook</see>
556
/// s should always try to use
557
/// <see cref="ReceiveCommand.SetResult(Result, string)">ReceiveCommand.SetResult(Result, string)
559
/// with a result status of
560
/// <see cref="Result.REJECTED_OTHER_REASON">Result.REJECTED_OTHER_REASON</see>
561
/// to indicate any reasons for
562
/// rejecting an update. Messages attached to a command are much more likely
563
/// to be returned to the client.
565
/// <param name="what">
566
/// string describing the problem identified by the hook. The
567
/// string must not end with an LF, and must not contain an LF.
569
public virtual void SendError(string what)
573
if (advertiseError == null)
575
advertiseError = new StringBuilder();
577
advertiseError.Append(what).Append('\n');
585
msgOut.Write(Constants.Encode("error: " + what + "\n"));
594
// Ignore write failures.
595
/// <summary>Send a message to the client, if it supports receiving them.</summary>
597
/// Send a message to the client, if it supports receiving them.
599
/// If the client doesn't support receiving messages, the message will be
600
/// discarded, with no other indication to the caller or to the client.
602
/// <param name="what">
603
/// string describing the problem identified by the hook. The
604
/// string must not end with an LF, and must not contain an LF.
606
public virtual void SendMessage(string what)
612
msgOut.Write(Constants.Encode(what + "\n"));
620
// Ignore write failures.
621
/// <summary>Execute the receive task on the socket.</summary>
622
/// <remarks>Execute the receive task on the socket.</remarks>
623
/// <param name="input">
624
/// raw input to read client commands and pack data from. Caller
625
/// must ensure the input is buffered, otherwise read performance
628
/// <param name="output">
629
/// response back to the Git network client. Caller must ensure
630
/// the output is buffered, otherwise write performance may
633
/// <param name="messages">
634
/// secondary "notice" channel to send additional messages out
635
/// through. When run over SSH this should be tied back to the
636
/// standard error channel of the command execution. For most
637
/// other network connections this should be null.
639
/// <exception cref="System.IO.IOException">System.IO.IOException</exception>
640
public virtual void Receive(InputStream input, OutputStream output, OutputStream
650
Sharpen.Thread caller = Sharpen.Thread.CurrentThread();
651
timer = new InterruptTimer(caller.GetName() + "-Timer");
652
timeoutIn = new TimeoutInputStream(rawIn, timer);
653
TimeoutOutputStream o = new TimeoutOutputStream(rawOut, timer);
654
timeoutIn.SetTimeout(timeout * 1000);
655
o.SetTimeout(timeout * 1000);
659
pckIn = new PacketLineIn(rawIn);
660
pckOut = new PacketLineOut(rawOut);
661
pckOut.SetFlushOnEnd(false);
662
enabledCapablities = new HashSet<string>();
663
commands = new AList<ReceiveCommand>();
673
// If we are using side band, we need to send a final
674
// flush-pkt to tell the remote peer the side band is
675
// complete and it should stop decoding. We need to
676
// use the original output stream as rawOut is now the
677
// side band data channel.
679
((SideBandOutputStream)msgOut).FlushBuffer();
680
((SideBandOutputStream)rawOut).FlushBuffer();
681
PacketLineOut plo = new PacketLineOut(output);
682
plo.SetFlushOnEnd(false);
685
if (biDirectionalPipe)
687
// If this was a native git connection, flush the pipe for
688
// the caller. For smart HTTP we don't do this flush and
689
// instead let the higher level HTTP servlet code do it.
691
if (!sideBand && msgOut != null)
708
enabledCapablities = null;
725
/// <exception cref="System.IO.IOException"></exception>
726
private void Service()
728
if (biDirectionalPipe)
730
SendAdvertisedRefs(new RefAdvertiser.PacketLineOutRefAdvertiser(pckOut));
737
if (advertiseError != null)
742
if (!commands.IsEmpty())
744
EnableCapabilities();
750
if (NeedCheckConnectivity())
757
catch (IOException err)
761
catch (RuntimeException err)
770
if (unpackError == null)
778
SendStatusReport(true, new _Reporter_685(this));
785
SendStatusReport(false, new _Reporter_692(this));
788
postReceive.OnPostReceive(this, FilterCommands(ReceiveCommand.Result.OK));
789
if (unpackError != null)
791
throw new UnpackException(unpackError);
796
private sealed class _Reporter_685 : ReceivePack.Reporter
798
public _Reporter_685(ReceivePack _enclosing)
800
this._enclosing = _enclosing;
803
/// <exception cref="System.IO.IOException"></exception>
804
internal override void SendString(string s)
806
this._enclosing.pckOut.WriteString(s + "\n");
809
private readonly ReceivePack _enclosing;
812
private sealed class _Reporter_692 : ReceivePack.Reporter
814
public _Reporter_692(ReceivePack _enclosing)
816
this._enclosing = _enclosing;
819
/// <exception cref="System.IO.IOException"></exception>
820
internal override void SendString(string s)
822
this._enclosing.msgOut.Write(Constants.Encode(s + "\n"));
825
private readonly ReceivePack _enclosing;
828
/// <exception cref="System.IO.IOException"></exception>
829
private void UnlockPack()
831
if (packLock != null)
838
/// <summary>Generate an advertisement of available refs and capabilities.</summary>
839
/// <remarks>Generate an advertisement of available refs and capabilities.</remarks>
840
/// <param name="adv">the advertisement formatter.</param>
841
/// <exception cref="System.IO.IOException">the formatter failed to write an advertisement.
843
public virtual void SendAdvertisedRefs(RefAdvertiser adv)
845
if (advertiseError != null)
847
adv.WriteOne("ERR " + advertiseError);
851
adv.AdvertiseCapability(BasePackPushConnection.CAPABILITY_SIDE_BAND_64K);
852
adv.AdvertiseCapability(BasePackPushConnection.CAPABILITY_DELETE_REFS);
853
adv.AdvertiseCapability(BasePackPushConnection.CAPABILITY_REPORT_STATUS);
856
adv.AdvertiseCapability(BasePackPushConnection.CAPABILITY_OFS_DELTA);
858
adv.Send(GetAdvertisedRefs());
859
foreach (ObjectId obj in advertisedHaves)
861
adv.AdvertiseHave(obj);
865
adv.AdvertiseId(ObjectId.ZeroId, "capabilities^{}");
870
/// <exception cref="System.IO.IOException"></exception>
871
private void RecvCommands()
878
line = pckIn.ReadStringRaw();
880
catch (EOFException eof)
882
if (commands.IsEmpty())
888
if (line == PacketLineIn.END)
892
if (commands.IsEmpty())
894
int nul = line.IndexOf('\0');
897
foreach (string c in Sharpen.Runtime.Substring(line, nul + 1).Split(" "))
899
enabledCapablities.AddItem(c);
901
line = Sharpen.Runtime.Substring(line, 0, nul);
904
if (line.Length < 83)
906
string m = JGitText.Get().errorInvalidProtocolWantedOldNewRef;
908
throw new PackProtocolException(m);
910
ObjectId oldId = ObjectId.FromString(Sharpen.Runtime.Substring(line, 0, 40));
911
ObjectId newId = ObjectId.FromString(Sharpen.Runtime.Substring(line, 41, 81));
912
string name = Sharpen.Runtime.Substring(line, 82);
913
ReceiveCommand cmd = new ReceiveCommand(oldId, newId, name);
914
if (name.Equals(Constants.HEAD))
916
cmd.SetResult(ReceiveCommand.Result.REJECTED_CURRENT_BRANCH);
920
cmd.SetRef(refs.Get(cmd.GetRefName()));
922
commands.AddItem(cmd);
926
private void EnableCapabilities()
928
reportStatus = enabledCapablities.Contains(BasePackPushConnection.CAPABILITY_REPORT_STATUS
930
sideBand = enabledCapablities.Contains(BasePackPushConnection.CAPABILITY_SIDE_BAND_64K
934
OutputStream @out = rawOut;
935
rawOut = new SideBandOutputStream(SideBandOutputStream.CH_DATA, SideBandOutputStream
937
msgOut = new SideBandOutputStream(SideBandOutputStream.CH_PROGRESS, SideBandOutputStream
939
pckOut = new PacketLineOut(rawOut);
940
pckOut.SetFlushOnEnd(false);
944
private bool NeedPack()
946
foreach (ReceiveCommand cmd in commands)
948
if (cmd.GetType() != ReceiveCommand.Type.DELETE)
956
/// <exception cref="System.IO.IOException"></exception>
957
private void DoReceivePack()
959
// It might take the client a while to pack the objects it needs
960
// to send to us. We should increase our timeout so we don't
961
// abort while the client is computing.
963
if (timeoutIn != null)
965
timeoutIn.SetTimeout(10 * timeout * 1000);
967
ProgressMonitor receiving = NullProgressMonitor.INSTANCE;
968
ProgressMonitor resolving = NullProgressMonitor.INSTANCE;
971
resolving = new SideBandProgressMonitor(msgOut);
973
ObjectInserter ins = db.NewObjectInserter();
976
string lockMsg = "jgit receive-pack";
977
if (GetRefLogIdent() != null)
979
lockMsg += " from " + GetRefLogIdent().ToExternalString();
981
parser = ins.NewPackParser(rawIn);
982
parser.SetAllowThin(true);
983
parser.SetNeedNewObjectIds(checkReferencedIsReachable);
984
parser.SetNeedBaseObjectIds(checkReferencedIsReachable);
985
parser.SetObjectChecking(IsCheckReceivedObjects());
986
parser.SetLockMessage(lockMsg);
987
packLock = parser.Parse(receiving, resolving);
994
if (timeoutIn != null)
996
timeoutIn.SetTimeout(timeout * 1000);
1000
private bool NeedCheckConnectivity()
1002
return IsCheckReceivedObjects() || IsCheckReferencedObjectsAreReachable();
1005
/// <exception cref="System.IO.IOException"></exception>
1006
private void CheckConnectivity()
1008
ObjectIdSubclassMap<ObjectId> baseObjects = null;
1009
ObjectIdSubclassMap<ObjectId> providedObjects = null;
1010
if (checkReferencedIsReachable)
1012
baseObjects = parser.GetBaseObjectIds();
1013
providedObjects = parser.GetNewObjectIds();
1016
ObjectWalk ow = new ObjectWalk(db);
1017
ow.SetRetainBody(false);
1018
if (checkReferencedIsReachable)
1020
ow.Sort(RevSort.TOPO);
1021
if (!baseObjects.IsEmpty())
1023
ow.Sort(RevSort.BOUNDARY, true);
1026
foreach (ReceiveCommand cmd in commands)
1028
if (cmd.GetResult() != ReceiveCommand.Result.NOT_ATTEMPTED)
1032
if (cmd.GetType() == ReceiveCommand.Type.DELETE)
1036
ow.MarkStart(ow.ParseAny(cmd.GetNewId()));
1038
foreach (ObjectId have in advertisedHaves)
1040
RevObject o = ow.ParseAny(have);
1041
ow.MarkUninteresting(o);
1042
if (checkReferencedIsReachable && !baseObjects.IsEmpty())
1047
o = ((RevCommit)o).Tree;
1051
ow.MarkUninteresting(o);
1056
while ((c = ow.Next()) != null)
1058
if (checkReferencedIsReachable && !c.Has(RevFlag.UNINTERESTING) && !providedObjects
1063
throw new MissingObjectException(c, Constants.TYPE_COMMIT);
1067
while ((o_1 = ow.NextObject()) != null)
1069
if (o_1.Has(RevFlag.UNINTERESTING))
1073
if (checkReferencedIsReachable)
1075
if (providedObjects.Contains(o_1))
1081
throw new MissingObjectException(o_1, o_1.Type);
1084
if (o_1 is RevBlob && !db.HasObject(o_1))
1086
throw new MissingObjectException(o_1, Constants.TYPE_BLOB);
1089
if (checkReferencedIsReachable)
1091
foreach (ObjectId id in baseObjects)
1093
o_1 = ow.ParseAny(id);
1094
if (!o_1.Has(RevFlag.UNINTERESTING))
1096
throw new MissingObjectException(o_1, o_1.Type);
1102
private void ValidateCommands()
1104
foreach (ReceiveCommand cmd in commands)
1106
Ref @ref = cmd.GetRef();
1107
if (cmd.GetResult() != ReceiveCommand.Result.NOT_ATTEMPTED)
1111
if (cmd.GetType() == ReceiveCommand.Type.DELETE && !IsAllowDeletes())
1113
// Deletes are not supported on this repository.
1115
cmd.SetResult(ReceiveCommand.Result.REJECTED_NODELETE);
1118
if (cmd.GetType() == ReceiveCommand.Type.CREATE)
1120
if (!IsAllowCreates())
1122
cmd.SetResult(ReceiveCommand.Result.REJECTED_NOCREATE);
1125
if (@ref != null && !IsAllowNonFastForwards())
1127
// Creation over an existing ref is certainly not going
1128
// to be a fast-forward update. We can reject it early.
1130
cmd.SetResult(ReceiveCommand.Result.REJECTED_NONFASTFORWARD);
1135
// A well behaved client shouldn't have sent us a
1136
// create command for a ref we advertised to it.
1138
cmd.SetResult(ReceiveCommand.Result.REJECTED_OTHER_REASON, "ref exists");
1142
if (cmd.GetType() == ReceiveCommand.Type.DELETE && @ref != null && !ObjectId.ZeroId
1143
.Equals(cmd.GetOldId()) && !@ref.GetObjectId().Equals(cmd.GetOldId()))
1145
// Delete commands can be sent with the old id matching our
1146
// advertised value, *OR* with the old id being 0{40}. Any
1147
// other requested old id is invalid.
1149
cmd.SetResult(ReceiveCommand.Result.REJECTED_OTHER_REASON, JGitText.Get().invalidOldIdSent
1153
if (cmd.GetType() == ReceiveCommand.Type.UPDATE)
1157
// The ref must have been advertised in order to be updated.
1159
cmd.SetResult(ReceiveCommand.Result.REJECTED_OTHER_REASON, JGitText.Get().noSuchRef
1163
if (!@ref.GetObjectId().Equals(cmd.GetOldId()))
1165
// A properly functioning client will send the same
1166
// object id we advertised.
1168
cmd.SetResult(ReceiveCommand.Result.REJECTED_OTHER_REASON, JGitText.Get().invalidOldIdSent
1172
// Is this possibly a non-fast-forward style update?
1178
oldObj = walk.ParseAny(cmd.GetOldId());
1182
cmd.SetResult(ReceiveCommand.Result.REJECTED_MISSING_OBJECT, cmd.GetOldId().Name);
1187
newObj = walk.ParseAny(cmd.GetNewId());
1191
cmd.SetResult(ReceiveCommand.Result.REJECTED_MISSING_OBJECT, cmd.GetNewId().Name);
1194
if (oldObj is RevCommit && newObj is RevCommit)
1198
if (!walk.IsMergedInto((RevCommit)oldObj, (RevCommit)newObj))
1200
cmd.SetType(ReceiveCommand.Type.UPDATE_NONFASTFORWARD);
1203
catch (MissingObjectException e)
1205
cmd.SetResult(ReceiveCommand.Result.REJECTED_MISSING_OBJECT, e.Message);
1209
cmd.SetResult(ReceiveCommand.Result.REJECTED_OTHER_REASON);
1214
cmd.SetType(ReceiveCommand.Type.UPDATE_NONFASTFORWARD);
1217
if (!cmd.GetRefName().StartsWith(Constants.R_REFS) || !Repository.IsValidRefName(
1220
cmd.SetResult(ReceiveCommand.Result.REJECTED_OTHER_REASON, JGitText.Get().funnyRefname
1226
private void ExecuteCommands()
1228
preReceive.OnPreReceive(this, FilterCommands(ReceiveCommand.Result.NOT_ATTEMPTED)
1230
foreach (ReceiveCommand cmd in FilterCommands(ReceiveCommand.Result.NOT_ATTEMPTED
1237
private void Execute(ReceiveCommand cmd)
1241
RefUpdate ru = db.UpdateRef(cmd.GetRefName());
1242
ru.SetRefLogIdent(GetRefLogIdent());
1243
switch (cmd.GetType())
1245
case ReceiveCommand.Type.DELETE:
1247
if (!ObjectId.ZeroId.Equals(cmd.GetOldId()))
1249
// We can only do a CAS style delete if the client
1250
// didn't bork its delete request by sending the
1251
// wrong zero id rather than the advertised one.
1253
ru.SetExpectedOldObjectId(cmd.GetOldId());
1255
ru.SetForceUpdate(true);
1256
Status(cmd, ru.Delete(walk));
1260
case ReceiveCommand.Type.CREATE:
1261
case ReceiveCommand.Type.UPDATE:
1262
case ReceiveCommand.Type.UPDATE_NONFASTFORWARD:
1264
ru.SetForceUpdate(IsAllowNonFastForwards());
1265
ru.SetExpectedOldObjectId(cmd.GetOldId());
1266
ru.SetNewObjectId(cmd.GetNewId());
1267
ru.SetRefLogMessage("push", true);
1268
Status(cmd, ru.Update(walk));
1273
catch (IOException err)
1275
cmd.SetResult(ReceiveCommand.Result.REJECTED_OTHER_REASON, MessageFormat.Format(JGitText
1276
.Get().lockError, err.Message));
1280
private void Status(ReceiveCommand cmd, RefUpdate.Result result)
1284
case RefUpdate.Result.NOT_ATTEMPTED:
1286
cmd.SetResult(ReceiveCommand.Result.NOT_ATTEMPTED);
1290
case RefUpdate.Result.LOCK_FAILURE:
1291
case RefUpdate.Result.IO_FAILURE:
1293
cmd.SetResult(ReceiveCommand.Result.LOCK_FAILURE);
1297
case RefUpdate.Result.NO_CHANGE:
1298
case RefUpdate.Result.NEW:
1299
case RefUpdate.Result.FORCED:
1300
case RefUpdate.Result.FAST_FORWARD:
1302
cmd.SetResult(ReceiveCommand.Result.OK);
1306
case RefUpdate.Result.REJECTED:
1308
cmd.SetResult(ReceiveCommand.Result.REJECTED_NONFASTFORWARD);
1312
case RefUpdate.Result.REJECTED_CURRENT_BRANCH:
1314
cmd.SetResult(ReceiveCommand.Result.REJECTED_CURRENT_BRANCH);
1320
cmd.SetResult(ReceiveCommand.Result.REJECTED_OTHER_REASON, result.ToString());
1327
private IList<ReceiveCommand> FilterCommands(ReceiveCommand.Result want)
1329
IList<ReceiveCommand> r = new AList<ReceiveCommand>(commands.Count);
1330
foreach (ReceiveCommand cmd in commands)
1332
if (cmd.GetResult() == want)
1340
/// <exception cref="System.IO.IOException"></exception>
1341
private void SendStatusReport(bool forClient, ReceivePack.Reporter @out)
1343
if (unpackError != null)
1345
@out.SendString("unpack error " + unpackError.Message);
1348
foreach (ReceiveCommand cmd in commands)
1350
@out.SendString("ng " + cmd.GetRefName() + " n/a (unpacker error)");
1357
@out.SendString("unpack ok");
1359
foreach (ReceiveCommand cmd_1 in commands)
1361
if (cmd_1.GetResult() == ReceiveCommand.Result.OK)
1365
@out.SendString("ok " + cmd_1.GetRefName());
1369
StringBuilder r = new StringBuilder();
1371
r.Append(cmd_1.GetRefName());
1373
switch (cmd_1.GetResult())
1375
case ReceiveCommand.Result.NOT_ATTEMPTED:
1377
r.Append("server bug; ref not processed");
1381
case ReceiveCommand.Result.REJECTED_NOCREATE:
1383
r.Append("creation prohibited");
1387
case ReceiveCommand.Result.REJECTED_NODELETE:
1389
r.Append("deletion prohibited");
1393
case ReceiveCommand.Result.REJECTED_NONFASTFORWARD:
1395
r.Append("non-fast forward");
1399
case ReceiveCommand.Result.REJECTED_CURRENT_BRANCH:
1401
r.Append("branch is currently checked out");
1405
case ReceiveCommand.Result.REJECTED_MISSING_OBJECT:
1407
if (cmd_1.GetMessage() == null)
1409
r.Append("missing object(s)");
1413
if (cmd_1.GetMessage().Length == Constants.OBJECT_ID_STRING_LENGTH)
1415
r.Append("object " + cmd_1.GetMessage() + " missing");
1419
r.Append(cmd_1.GetMessage());
1425
case ReceiveCommand.Result.REJECTED_OTHER_REASON:
1427
if (cmd_1.GetMessage() == null)
1429
r.Append("unspecified reason");
1433
r.Append(cmd_1.GetMessage());
1438
case ReceiveCommand.Result.LOCK_FAILURE:
1440
r.Append("failed to lock");
1444
case ReceiveCommand.Result.OK:
1446
// We shouldn't have reached this case (see 'ok' case above).
1450
@out.SendString(r.ToString());
1454
internal abstract class Reporter
1456
/// <exception cref="System.IO.IOException"></exception>
1457
internal abstract void SendString(string s);