45
using System.Collections.Generic;
52
using NGit.Storage.File;
53
48
using NGit.Transport;
57
51
namespace NGit.Transport
59
53
/// <summary>Implements the server side of a push connection, receiving objects.</summary>
60
54
/// <remarks>Implements the server side of a push connection, receiving objects.</remarks>
61
public class ReceivePack
55
public class ReceivePack : BaseReceivePack
63
/// <summary>Data in the first line of a request, the line itself plus capabilities.</summary>
64
/// <remarks>Data in the first line of a request, the line itself plus capabilities.</remarks>
65
public class FirstLine
67
private readonly string line;
69
private readonly ICollection<string> capabilities;
71
/// <summary>Parse the first line of a receive-pack request.</summary>
72
/// <remarks>Parse the first line of a receive-pack request.</remarks>
73
/// <param name="line">line from the client.</param>
74
public FirstLine(string line)
76
HashSet<string> caps = new HashSet<string>();
77
int nul = line.IndexOf('\0');
80
foreach (string c in Sharpen.Runtime.Substring(line, nul + 1).Split(" "))
84
this.line = Sharpen.Runtime.Substring(line, 0, nul);
90
this.capabilities = Sharpen.Collections.UnmodifiableSet(caps);
93
/// <returns>non-capabilities part of the line.</returns>
94
public virtual string GetLine()
99
/// <returns>capabilities parsed from the line.</returns>
100
public virtual ICollection<string> GetCapabilities()
106
/// <summary>Database we write the stored objects into.</summary>
107
/// <remarks>Database we write the stored objects into.</remarks>
108
private readonly Repository db;
111
/// Revision traversal support over
112
/// <see cref="db">db</see>
115
private readonly RevWalk walk;
118
/// Is the client connection a bi-directional socket or pipe?
120
/// If true, this class assumes it can perform multiple read and write cycles
121
/// with the client over the input and output streams.
124
/// Is the client connection a bi-directional socket or pipe?
126
/// If true, this class assumes it can perform multiple read and write cycles
127
/// with the client over the input and output streams. This matches the
128
/// functionality available with a standard TCP/IP connection, or a local
129
/// operating system or in-memory pipe.
131
/// If false, this class runs in a read everything then output results mode,
132
/// making it suitable for single round-trip systems RPCs such as HTTP.
134
private bool biDirectionalPipe = true;
136
/// <summary>Should an incoming transfer validate objects?</summary>
137
private bool checkReceivedObjects;
139
/// <summary>Should an incoming transfer permit create requests?</summary>
140
private bool allowCreates;
142
/// <summary>Should an incoming transfer permit delete requests?</summary>
143
private bool allowDeletes;
145
/// <summary>Should an incoming transfer permit non-fast-forward requests?</summary>
146
private bool allowNonFastForwards;
148
private bool allowOfsDelta;
150
/// <summary>Identity to record action as within the reflog.</summary>
151
/// <remarks>Identity to record action as within the reflog.</remarks>
152
private PersonIdent refLogIdent;
154
/// <summary>Hook used while advertising the refs to the client.</summary>
155
/// <remarks>Hook used while advertising the refs to the client.</remarks>
156
private AdvertiseRefsHook advertiseRefsHook;
158
/// <summary>Filter used while advertising the refs to the client.</summary>
159
/// <remarks>Filter used while advertising the refs to the client.</remarks>
160
private RefFilter refFilter;
162
57
/// <summary>Hook to validate the update commands before execution.</summary>
163
58
/// <remarks>Hook to validate the update commands before execution.</remarks>
164
59
private PreReceiveHook preReceive;
227
71
private bool reportStatus;
231
/// <see cref="BasePackPushConnection.CAPABILITY_SIDE_BAND_64K">BasePackPushConnection.CAPABILITY_SIDE_BAND_64K
235
private bool sideBand;
237
/// <summary>Lock around the received pack file, while updating refs.</summary>
238
/// <remarks>Lock around the received pack file, while updating refs.</remarks>
239
private PackLock packLock;
241
private bool checkReferencedIsReachable;
243
/// <summary>Git object size limit</summary>
244
private long maxObjectSizeLimit;
73
private bool echoCommandFailures;
246
75
/// <summary>Create a new pack receive for an open repository.</summary>
247
76
/// <remarks>Create a new pack receive for an open repository.</remarks>
248
77
/// <param name="into">the destination repository.</param>
249
public ReceivePack(Repository into)
78
protected internal ReceivePack(Repository into) : base(into)
251
msgOutWrapper = new ReceivePack.MessageOutputWrapper(this);
253
walk = new RevWalk(db);
254
ReceivePack.ReceiveConfig cfg = db.GetConfig().Get(ReceivePack.ReceiveConfig.KEY);
255
checkReceivedObjects = cfg.checkReceivedObjects;
256
allowCreates = cfg.allowCreates;
257
allowDeletes = cfg.allowDeletes;
258
allowNonFastForwards = cfg.allowNonFastForwards;
259
allowOfsDelta = cfg.allowOfsDelta;
260
advertiseRefsHook = AdvertiseRefsHook.DEFAULT;
261
refFilter = RefFilter.DEFAULT;
262
80
preReceive = PreReceiveHook.NULL;
263
81
postReceive = PostReceiveHook.NULL;
264
advertisedHaves = new HashSet<ObjectId>();
267
private class ReceiveConfig
269
private sealed class _SectionParser_261 : Config.SectionParser<ReceivePack.ReceiveConfig
272
public _SectionParser_261()
276
public ReceivePack.ReceiveConfig Parse(Config cfg)
278
return new ReceivePack.ReceiveConfig(cfg);
282
internal static readonly Config.SectionParser<ReceivePack.ReceiveConfig> KEY = new
283
_SectionParser_261();
285
internal readonly bool checkReceivedObjects;
287
internal readonly bool allowCreates;
289
internal readonly bool allowDeletes;
291
internal readonly bool allowNonFastForwards;
293
internal readonly bool allowOfsDelta;
295
internal ReceiveConfig(Config config)
297
checkReceivedObjects = config.GetBoolean("receive", "fsckobjects", false);
299
allowDeletes = !config.GetBoolean("receive", "denydeletes", false);
300
allowNonFastForwards = !config.GetBoolean("receive", "denynonfastforwards", false
302
allowOfsDelta = config.GetBoolean("repack", "usedeltabaseoffset", true);
307
/// Output stream that wraps the current
308
/// <see cref="ReceivePack.msgOut">ReceivePack.msgOut</see>
311
/// We don't want to expose
312
/// <see cref="ReceivePack.msgOut">ReceivePack.msgOut</see>
313
/// directly because it can change
314
/// several times over the course of a session.
316
private class MessageOutputWrapper : OutputStream
318
public override void Write(int ch)
320
if (this._enclosing.msgOut != null)
324
this._enclosing.msgOut.Write(ch);
332
// Ignore write failures.
333
public override void Write(byte[] b, int off, int len)
335
if (this._enclosing.msgOut != null)
339
this._enclosing.msgOut.Write(b, off, len);
347
// Ignore write failures.
348
public override void Write(byte[] b)
350
this.Write(b, 0, b.Length);
353
public override void Flush()
355
if (this._enclosing.msgOut != null)
359
this._enclosing.msgOut.Flush();
367
internal MessageOutputWrapper(ReceivePack _enclosing)
369
this._enclosing = _enclosing;
372
private readonly ReceivePack _enclosing;
373
// Ignore write failures.
376
/// <returns>the repository this receive completes into.</returns>
377
public Repository GetRepository()
382
/// <returns>the RevWalk instance used by this connection.</returns>
383
public RevWalk GetRevWalk()
388
/// <summary>Get refs which were advertised to the client.</summary>
389
/// <remarks>Get refs which were advertised to the client.</remarks>
391
/// all refs which were advertised to the client, or null if
392
/// <see cref="SetAdvertisedRefs(System.Collections.Generic.IDictionary{K, V}, System.Collections.Generic.ICollection{E})
393
/// ">SetAdvertisedRefs(System.Collections.Generic.IDictionary<K, V>, System.Collections.Generic.ICollection<E>)
395
/// has not been called yet.
397
public IDictionary<string, Ref> GetAdvertisedRefs()
402
/// <summary>Set the refs advertised by this ReceivePack.</summary>
404
/// Set the refs advertised by this ReceivePack.
406
/// Intended to be called from a
407
/// <see cref="PreReceiveHook">PreReceiveHook</see>
410
/// <param name="allRefs">
411
/// explicit set of references to claim as advertised by this
412
/// ReceivePack instance. This overrides any references that
413
/// may exist in the source repository. The map is passed
414
/// to the configured
415
/// <see cref="GetRefFilter()">GetRefFilter()</see>
416
/// . If null, assumes
417
/// all refs were advertised.
419
/// <param name="additionalHaves">
420
/// explicit set of additional haves to claim as advertised. If
421
/// null, assumes the default set of additional haves from the
424
public virtual void SetAdvertisedRefs(IDictionary<string, Ref> allRefs, ICollection
425
<ObjectId> additionalHaves)
427
refs = allRefs != null ? allRefs : db.GetAllRefs();
428
refs = refFilter.Filter(refs);
429
Ref head = refs.Get(Constants.HEAD);
430
if (head != null && head.IsSymbolic())
432
Sharpen.Collections.Remove(refs, Constants.HEAD);
434
foreach (Ref @ref in refs.Values)
436
if (@ref.GetObjectId() != null)
438
advertisedHaves.AddItem(@ref.GetObjectId());
441
if (additionalHaves != null)
443
Sharpen.Collections.AddAll(advertisedHaves, additionalHaves);
447
Sharpen.Collections.AddAll(advertisedHaves, db.GetAdditionalHaves());
451
/// <summary>Get objects advertised to the client.</summary>
452
/// <remarks>Get objects advertised to the client.</remarks>
454
/// the set of objects advertised to the as present in this repository,
456
/// <see cref="SetAdvertisedRefs(System.Collections.Generic.IDictionary{K, V}, System.Collections.Generic.ICollection{E})
457
/// ">SetAdvertisedRefs(System.Collections.Generic.IDictionary<K, V>, System.Collections.Generic.ICollection<E>)
459
/// has not been called
462
public ICollection<ObjectId> GetAdvertisedObjects()
464
return advertisedHaves;
468
/// true if this instance will validate all referenced, but not
469
/// supplied by the client, objects are reachable from another
472
public virtual bool IsCheckReferencedObjectsAreReachable()
474
return checkReferencedIsReachable;
477
/// <summary>Validate all referenced but not supplied objects are reachable.</summary>
479
/// Validate all referenced but not supplied objects are reachable.
481
/// If enabled, this instance will verify that references to objects not
482
/// contained within the received pack are already reachable through at least
483
/// one other reference displayed as part of
484
/// <see cref="GetAdvertisedRefs()">GetAdvertisedRefs()</see>
487
/// This feature is useful when the application doesn't trust the client to
488
/// not provide a forged SHA-1 reference to an object, in an attempt to
489
/// access parts of the DAG that they aren't allowed to see and which have
490
/// been hidden from them via the configured
491
/// <see cref="AdvertiseRefsHook">AdvertiseRefsHook</see>
493
/// <see cref="RefFilter">RefFilter</see>
496
/// Enabling this feature may imply at least some, if not all, of the same
497
/// functionality performed by
498
/// <see cref="SetCheckReceivedObjects(bool)">SetCheckReceivedObjects(bool)</see>
500
/// Applications are encouraged to enable both features, if desired.
503
/// <code>true</code>
504
/// to enable the additional check.
506
public virtual void SetCheckReferencedObjectsAreReachable(bool b)
508
this.checkReferencedIsReachable = b;
512
/// true if this class expects a bi-directional pipe opened between
513
/// the client and itself. The default is true.
515
public virtual bool IsBiDirectionalPipe()
517
return biDirectionalPipe;
520
/// <param name="twoWay">
521
/// if true, this class will assume the socket is a fully
522
/// bidirectional pipe between the two peers and takes advantage
523
/// of that by first transmitting the known refs, then waiting to
524
/// read commands. If false, this class assumes it must read the
525
/// commands before writing output and does not perform the
526
/// initial advertising.
528
public virtual void SetBiDirectionalPipe(bool twoWay)
530
biDirectionalPipe = twoWay;
534
/// true if this instance will verify received objects are formatted
535
/// correctly. Validating objects requires more CPU time on this side
536
/// of the connection.
538
public virtual bool IsCheckReceivedObjects()
540
return checkReceivedObjects;
543
/// <param name="check">
544
/// true to enable checking received objects; false to assume all
545
/// received objects are valid.
547
public virtual void SetCheckReceivedObjects(bool check)
549
checkReceivedObjects = check;
552
/// <returns>true if the client can request refs to be created.</returns>
553
public virtual bool IsAllowCreates()
558
/// <param name="canCreate">true to permit create ref commands to be processed.</param>
559
public virtual void SetAllowCreates(bool canCreate)
561
allowCreates = canCreate;
564
/// <returns>true if the client can request refs to be deleted.</returns>
565
public virtual bool IsAllowDeletes()
570
/// <param name="canDelete">true to permit delete ref commands to be processed.</param>
571
public virtual void SetAllowDeletes(bool canDelete)
573
allowDeletes = canDelete;
577
/// true if the client can request non-fast-forward updates of a ref,
578
/// possibly making objects unreachable.
580
public virtual bool IsAllowNonFastForwards()
582
return allowNonFastForwards;
585
/// <param name="canRewind">
586
/// true to permit the client to ask for non-fast-forward updates
587
/// of an existing ref.
589
public virtual void SetAllowNonFastForwards(bool canRewind)
591
allowNonFastForwards = canRewind;
594
/// <returns>identity of the user making the changes in the reflog.</returns>
595
public virtual PersonIdent GetRefLogIdent()
600
/// <summary>Set the identity of the user appearing in the affected reflogs.</summary>
602
/// Set the identity of the user appearing in the affected reflogs.
604
/// The timestamp portion of the identity is ignored. A new identity with the
605
/// current timestamp will be created automatically when the updates occur
606
/// and the log records are written.
608
/// <param name="pi">
609
/// identity of the user. If null the identity will be
610
/// automatically determined based on the repository
613
public virtual void SetRefLogIdent(PersonIdent pi)
618
/// <returns>the hook used while advertising the refs to the client</returns>
619
public virtual AdvertiseRefsHook GetAdvertiseRefsHook()
621
return advertiseRefsHook;
624
/// <returns>the filter used while advertising the refs to the client</returns>
625
public virtual RefFilter GetRefFilter()
630
/// <summary>Set the hook used while advertising the refs to the client.</summary>
632
/// Set the hook used while advertising the refs to the client.
635
/// <see cref="AdvertiseRefsHook">AdvertiseRefsHook</see>
637
/// <see cref="SetAdvertisedRefs(System.Collections.Generic.IDictionary{K, V}, System.Collections.Generic.ICollection{E})
638
/// ">SetAdvertisedRefs(System.Collections.Generic.IDictionary<K, V>, System.Collections.Generic.ICollection<E>)
640
/// , only refs set by this hook
641
/// <em>and</em> selected by the
642
/// <see cref="RefFilter">RefFilter</see>
643
/// will be shown to the client.
644
/// Clients may still attempt to create or update a reference not advertised by
646
/// <see cref="AdvertiseRefsHook">AdvertiseRefsHook</see>
647
/// . These attempts should be rejected
649
/// <see cref="PreReceiveHook">PreReceiveHook</see>
652
/// <param name="advertiseRefsHook">the hook; may be null to show all refs.</param>
653
public virtual void SetAdvertiseRefsHook(AdvertiseRefsHook advertiseRefsHook)
655
if (advertiseRefsHook != null)
657
this.advertiseRefsHook = advertiseRefsHook;
661
this.advertiseRefsHook = AdvertiseRefsHook.DEFAULT;
665
/// <summary>Set the filter used while advertising the refs to the client.</summary>
667
/// Set the filter used while advertising the refs to the client.
669
/// Only refs allowed by this filter will be shown to the client.
670
/// The filter is run against the refs specified by the
671
/// <see cref="AdvertiseRefsHook">AdvertiseRefsHook</see>
674
/// <param name="refFilter">the filter; may be null to show all refs.</param>
675
public virtual void SetRefFilter(RefFilter refFilter)
677
this.refFilter = refFilter != null ? refFilter : RefFilter.DEFAULT;
680
84
/// <returns>the hook invoked before updates occur.</returns>
724
128
postReceive = h != null ? h : PostReceiveHook.NULL;
727
/// <returns>timeout (in seconds) before aborting an IO operation.</returns>
728
public virtual int GetTimeout()
733
/// <summary>Set the timeout before willing to abort an IO call.</summary>
734
/// <remarks>Set the timeout before willing to abort an IO call.</remarks>
735
/// <param name="seconds">
736
/// number of seconds to wait (with no data transfer occurring)
737
/// before aborting an IO read or write operation with the
738
/// connected client.
740
public virtual void SetTimeout(int seconds)
745
/// <summary>Set the maximum allowed Git object size.</summary>
747
/// Set the maximum allowed Git object size.
749
/// If an object is larger than the given size the pack-parsing will throw an
750
/// exception aborting the receive-pack operation.
752
/// <param name="limit">the Git object size limit. If zero then there is not limit.</param>
753
public virtual void SetMaxObjectSizeLimit(long limit)
755
maxObjectSizeLimit = limit;
758
/// <summary>Check whether the client expects a side-band stream.</summary>
759
/// <remarks>Check whether the client expects a side-band stream.</remarks>
761
/// true if the client has advertised a side-band capability, false
764
/// <exception cref="RequestNotYetReadException">
765
/// if the client's request has not yet been read from the wire, so
766
/// we do not know if they expect side-band. Note that the client
767
/// may have already written the request, it just has not been
770
/// <exception cref="NGit.Transport.RequestNotYetReadException"></exception>
771
public virtual bool IsSideBand()
773
if (enabledCapabilities == null)
775
throw new RequestNotYetReadException();
777
return enabledCapabilities.Contains(BasePackPushConnection.CAPABILITY_SIDE_BAND_64K
781
/// <returns>all of the command received by the current request.</returns>
782
public virtual IList<ReceiveCommand> GetAllCommands()
784
return Sharpen.Collections.UnmodifiableList(commands);
787
/// <summary>Send an error message to the client.</summary>
789
/// Send an error message to the client.
791
/// If any error messages are sent before the references are advertised to
792
/// the client, the errors will be sent instead of the advertisement and the
793
/// receive operation will be aborted. All clients should receive and display
794
/// such early stage errors.
796
/// If the reference advertisements have already been sent, messages are sent
797
/// in a side channel. If the client doesn't support receiving messages, the
798
/// message will be discarded, with no other indication to the caller or to
801
/// <see cref="PreReceiveHook">PreReceiveHook</see>
802
/// s should always try to use
803
/// <see cref="ReceiveCommand.SetResult(Result, string)">ReceiveCommand.SetResult(Result, string)
805
/// with a result status of
806
/// <see cref="Result.REJECTED_OTHER_REASON">Result.REJECTED_OTHER_REASON</see>
807
/// to indicate any reasons for
808
/// rejecting an update. Messages attached to a command are much more likely
809
/// to be returned to the client.
811
/// <param name="what">
812
/// string describing the problem identified by the hook. The
813
/// string must not end with an LF, and must not contain an LF.
815
public virtual void SendError(string what)
819
if (advertiseError == null)
821
advertiseError = new StringBuilder();
823
advertiseError.Append(what).Append('\n');
827
msgOutWrapper.Write(Constants.Encode("error: " + what + "\n"));
831
/// <summary>Send a message to the client, if it supports receiving them.</summary>
833
/// Send a message to the client, if it supports receiving them.
835
/// If the client doesn't support receiving messages, the message will be
836
/// discarded, with no other indication to the caller or to the client.
838
/// <param name="what">
839
/// string describing the problem identified by the hook. The
840
/// string must not end with an LF, and must not contain an LF.
842
public virtual void SendMessage(string what)
844
msgOutWrapper.Write(Constants.Encode(what + "\n"));
847
/// <returns>an underlying stream for sending messages to the client.</returns>
848
public virtual OutputStream GetMessageOutputStream()
850
return msgOutWrapper;
131
/// <param name="echo">
132
/// if true this class will report command failures as warning
133
/// messages before sending the command results. This is usually
134
/// not necessary, but may help buggy Git clients that discard the
135
/// errors when all branches fail.
137
public virtual void SetEchoCommandFailures(bool echo)
139
echoCommandFailures = echo;
853
142
/// <summary>Execute the receive task on the socket.</summary>
1066
315
private readonly ReceivePack _enclosing;
1069
/// <exception cref="System.IO.IOException"></exception>
1070
private void UnlockPack()
1072
if (packLock != null)
1079
/// <summary>Generate an advertisement of available refs and capabilities.</summary>
1080
/// <remarks>Generate an advertisement of available refs and capabilities.</remarks>
1081
/// <param name="adv">the advertisement formatter.</param>
1082
/// <exception cref="System.IO.IOException">the formatter failed to write an advertisement.
1084
/// <exception cref="ServiceMayNotContinueException">the hook denied advertisement.</exception>
1085
/// <exception cref="NGit.Transport.ServiceMayNotContinueException"></exception>
1086
public virtual void SendAdvertisedRefs(RefAdvertiser adv)
1088
if (advertiseError != null)
1090
adv.WriteOne("ERR " + advertiseError);
1095
advertiseRefsHook.AdvertiseRefs(this);
1097
catch (ServiceMayNotContinueException fail)
1099
if (fail.Message != null)
1101
adv.WriteOne("ERR " + fail.Message);
1107
adv.AdvertiseCapability(BasePackPushConnection.CAPABILITY_SIDE_BAND_64K);
1108
adv.AdvertiseCapability(BasePackPushConnection.CAPABILITY_DELETE_REFS);
1109
adv.AdvertiseCapability(BasePackPushConnection.CAPABILITY_REPORT_STATUS);
1112
adv.AdvertiseCapability(BasePackPushConnection.CAPABILITY_OFS_DELTA);
1114
adv.Send(GetAdvertisedOrDefaultRefs());
1115
foreach (ObjectId obj in advertisedHaves)
1117
adv.AdvertiseHave(obj);
1121
adv.AdvertiseId(ObjectId.ZeroId, "capabilities^{}");
1126
/// <exception cref="System.IO.IOException"></exception>
1127
private void RecvCommands()
1134
line = pckIn.ReadStringRaw();
1136
catch (EOFException eof)
1138
if (commands.IsEmpty())
1144
if (line == PacketLineIn.END)
1148
if (commands.IsEmpty())
1150
ReceivePack.FirstLine firstLine = new ReceivePack.FirstLine(line);
1151
enabledCapabilities = firstLine.GetCapabilities();
1152
line = firstLine.GetLine();
1154
if (line.Length < 83)
1156
string m = JGitText.Get().errorInvalidProtocolWantedOldNewRef;
1158
throw new PackProtocolException(m);
1160
ObjectId oldId = ObjectId.FromString(Sharpen.Runtime.Substring(line, 0, 40));
1161
ObjectId newId = ObjectId.FromString(Sharpen.Runtime.Substring(line, 41, 81));
1162
string name = Sharpen.Runtime.Substring(line, 82);
1163
ReceiveCommand cmd = new ReceiveCommand(oldId, newId, name);
1164
if (name.Equals(Constants.HEAD))
1166
cmd.SetResult(ReceiveCommand.Result.REJECTED_CURRENT_BRANCH);
1170
cmd.SetRef(refs.Get(cmd.GetRefName()));
1172
commands.AddItem(cmd);
1176
private void EnableCapabilities()
1178
reportStatus = enabledCapabilities.Contains(BasePackPushConnection.CAPABILITY_REPORT_STATUS
1180
sideBand = enabledCapabilities.Contains(BasePackPushConnection.CAPABILITY_SIDE_BAND_64K
1184
OutputStream @out = rawOut;
1185
rawOut = new SideBandOutputStream(SideBandOutputStream.CH_DATA, SideBandOutputStream
1187
msgOut = new SideBandOutputStream(SideBandOutputStream.CH_PROGRESS, SideBandOutputStream
1189
pckOut = new PacketLineOut(rawOut);
1190
pckOut.SetFlushOnEnd(false);
1194
private bool NeedPack()
1196
foreach (ReceiveCommand cmd in commands)
1198
if (cmd.GetType() != ReceiveCommand.Type.DELETE)
1206
/// <exception cref="System.IO.IOException"></exception>
1207
private void DoReceivePack()
1209
// It might take the client a while to pack the objects it needs
1210
// to send to us. We should increase our timeout so we don't
1211
// abort while the client is computing.
1213
if (timeoutIn != null)
1215
timeoutIn.SetTimeout(10 * timeout * 1000);
1217
ProgressMonitor receiving = NullProgressMonitor.INSTANCE;
1218
ProgressMonitor resolving = NullProgressMonitor.INSTANCE;
1221
resolving = new SideBandProgressMonitor(msgOut);
1223
ObjectInserter ins = db.NewObjectInserter();
1226
string lockMsg = "jgit receive-pack";
1227
if (GetRefLogIdent() != null)
1229
lockMsg += " from " + GetRefLogIdent().ToExternalString();
1231
parser = ins.NewPackParser(rawIn);
1232
parser.SetAllowThin(true);
1233
parser.SetNeedNewObjectIds(checkReferencedIsReachable);
1234
parser.SetNeedBaseObjectIds(checkReferencedIsReachable);
1235
parser.SetCheckEofAfterPackFooter(!biDirectionalPipe);
1236
parser.SetObjectChecking(IsCheckReceivedObjects());
1237
parser.SetLockMessage(lockMsg);
1238
parser.SetMaxObjectSizeLimit(maxObjectSizeLimit);
1239
packLock = parser.Parse(receiving, resolving);
1246
if (timeoutIn != null)
1248
timeoutIn.SetTimeout(timeout * 1000);
1252
private bool NeedCheckConnectivity()
1254
return IsCheckReceivedObjects() || IsCheckReferencedObjectsAreReachable();
1257
/// <exception cref="System.IO.IOException"></exception>
1258
private void CheckConnectivity()
1260
ObjectIdSubclassMap<ObjectId> baseObjects = null;
1261
ObjectIdSubclassMap<ObjectId> providedObjects = null;
1262
if (checkReferencedIsReachable)
1264
baseObjects = parser.GetBaseObjectIds();
1265
providedObjects = parser.GetNewObjectIds();
1268
ObjectWalk ow = new ObjectWalk(db);
1269
ow.SetRetainBody(false);
1270
if (checkReferencedIsReachable)
1272
ow.Sort(RevSort.TOPO);
1273
if (!baseObjects.IsEmpty())
1275
ow.Sort(RevSort.BOUNDARY, true);
1278
foreach (ReceiveCommand cmd in commands)
1280
if (cmd.GetResult() != ReceiveCommand.Result.NOT_ATTEMPTED)
1284
if (cmd.GetType() == ReceiveCommand.Type.DELETE)
1288
ow.MarkStart(ow.ParseAny(cmd.GetNewId()));
1290
foreach (ObjectId have in advertisedHaves)
1292
RevObject o = ow.ParseAny(have);
1293
ow.MarkUninteresting(o);
1294
if (checkReferencedIsReachable && !baseObjects.IsEmpty())
1299
o = ((RevCommit)o).Tree;
1303
ow.MarkUninteresting(o);
1308
while ((c = ow.Next()) != null)
1310
if (checkReferencedIsReachable && !c.Has(RevFlag.UNINTERESTING) && !providedObjects
1315
throw new MissingObjectException(c, Constants.TYPE_COMMIT);
1319
while ((o_1 = ow.NextObject()) != null)
1321
if (o_1.Has(RevFlag.UNINTERESTING))
1325
if (checkReferencedIsReachable)
1327
if (providedObjects.Contains(o_1))
1333
throw new MissingObjectException(o_1, o_1.Type);
1336
if (o_1 is RevBlob && !db.HasObject(o_1))
1338
throw new MissingObjectException(o_1, Constants.TYPE_BLOB);
1341
if (checkReferencedIsReachable)
1343
foreach (ObjectId id in baseObjects)
1345
o_1 = ow.ParseAny(id);
1346
if (!o_1.Has(RevFlag.UNINTERESTING))
1348
throw new MissingObjectException(o_1, o_1.Type);
1354
private void ValidateCommands()
1356
foreach (ReceiveCommand cmd in commands)
1358
Ref @ref = cmd.GetRef();
1359
if (cmd.GetResult() != ReceiveCommand.Result.NOT_ATTEMPTED)
1363
if (cmd.GetType() == ReceiveCommand.Type.DELETE && !IsAllowDeletes())
1365
// Deletes are not supported on this repository.
1367
cmd.SetResult(ReceiveCommand.Result.REJECTED_NODELETE);
1370
if (cmd.GetType() == ReceiveCommand.Type.CREATE)
1372
if (!IsAllowCreates())
1374
cmd.SetResult(ReceiveCommand.Result.REJECTED_NOCREATE);
1377
if (@ref != null && !IsAllowNonFastForwards())
1379
// Creation over an existing ref is certainly not going
1380
// to be a fast-forward update. We can reject it early.
1382
cmd.SetResult(ReceiveCommand.Result.REJECTED_NONFASTFORWARD);
1387
// A well behaved client shouldn't have sent us a
1388
// create command for a ref we advertised to it.
1390
cmd.SetResult(ReceiveCommand.Result.REJECTED_OTHER_REASON, MessageFormat.Format(JGitText
1391
.Get().refAlreadyExists, @ref));
1395
if (cmd.GetType() == ReceiveCommand.Type.DELETE && @ref != null && !ObjectId.ZeroId
1396
.Equals(cmd.GetOldId()) && !@ref.GetObjectId().Equals(cmd.GetOldId()))
1398
// Delete commands can be sent with the old id matching our
1399
// advertised value, *OR* with the old id being 0{40}. Any
1400
// other requested old id is invalid.
1402
cmd.SetResult(ReceiveCommand.Result.REJECTED_OTHER_REASON, JGitText.Get().invalidOldIdSent
1406
if (cmd.GetType() == ReceiveCommand.Type.UPDATE)
1410
// The ref must have been advertised in order to be updated.
1412
cmd.SetResult(ReceiveCommand.Result.REJECTED_OTHER_REASON, JGitText.Get().noSuchRef
1416
if (!@ref.GetObjectId().Equals(cmd.GetOldId()))
1418
// A properly functioning client will send the same
1419
// object id we advertised.
1421
cmd.SetResult(ReceiveCommand.Result.REJECTED_OTHER_REASON, JGitText.Get().invalidOldIdSent
1425
// Is this possibly a non-fast-forward style update?
1431
oldObj = walk.ParseAny(cmd.GetOldId());
1435
cmd.SetResult(ReceiveCommand.Result.REJECTED_MISSING_OBJECT, cmd.GetOldId().Name);
1440
newObj = walk.ParseAny(cmd.GetNewId());
1444
cmd.SetResult(ReceiveCommand.Result.REJECTED_MISSING_OBJECT, cmd.GetNewId().Name);
1447
if (oldObj is RevCommit && newObj is RevCommit)
1451
if (!walk.IsMergedInto((RevCommit)oldObj, (RevCommit)newObj))
1453
cmd.SetType(ReceiveCommand.Type.UPDATE_NONFASTFORWARD);
1456
catch (MissingObjectException e)
1458
cmd.SetResult(ReceiveCommand.Result.REJECTED_MISSING_OBJECT, e.Message);
1462
cmd.SetResult(ReceiveCommand.Result.REJECTED_OTHER_REASON);
1467
cmd.SetType(ReceiveCommand.Type.UPDATE_NONFASTFORWARD);
1470
if (!cmd.GetRefName().StartsWith(Constants.R_REFS) || !Repository.IsValidRefName(
1473
cmd.SetResult(ReceiveCommand.Result.REJECTED_OTHER_REASON, JGitText.Get().funnyRefname
1479
private void ExecuteCommands()
1481
preReceive.OnPreReceive(this, ReceiveCommand.Filter(commands, ReceiveCommand.Result
1483
IList<ReceiveCommand> toApply = ReceiveCommand.Filter(commands, ReceiveCommand.Result
1485
ProgressMonitor updating = NullProgressMonitor.INSTANCE;
1488
SideBandProgressMonitor pm = new SideBandProgressMonitor(msgOut);
1489
pm.SetDelayStart(250, TimeUnit.MILLISECONDS);
1492
updating.BeginTask(JGitText.Get().updatingReferences, toApply.Count);
1493
foreach (ReceiveCommand cmd in toApply)
1501
/// <exception cref="System.IO.IOException"></exception>
1502
private void SendStatusReport(bool forClient, ReceivePack.Reporter @out)
1504
if (unpackError != null)
1506
@out.SendString("unpack error " + unpackError.Message);
1509
foreach (ReceiveCommand cmd in commands)
1511
@out.SendString("ng " + cmd.GetRefName() + " n/a (unpacker error)");
1518
@out.SendString("unpack ok");
1520
foreach (ReceiveCommand cmd_1 in commands)
1522
if (cmd_1.GetResult() == ReceiveCommand.Result.OK)
1526
@out.SendString("ok " + cmd_1.GetRefName());
1530
StringBuilder r = new StringBuilder();
1532
r.Append(cmd_1.GetRefName());
1534
switch (cmd_1.GetResult())
1536
case ReceiveCommand.Result.NOT_ATTEMPTED:
1538
r.Append("server bug; ref not processed");
1542
case ReceiveCommand.Result.REJECTED_NOCREATE:
1544
r.Append("creation prohibited");
1548
case ReceiveCommand.Result.REJECTED_NODELETE:
1550
r.Append("deletion prohibited");
1554
case ReceiveCommand.Result.REJECTED_NONFASTFORWARD:
1556
r.Append("non-fast forward");
1560
case ReceiveCommand.Result.REJECTED_CURRENT_BRANCH:
1562
r.Append("branch is currently checked out");
1566
case ReceiveCommand.Result.REJECTED_MISSING_OBJECT:
1568
if (cmd_1.GetMessage() == null)
1570
r.Append("missing object(s)");
1574
if (cmd_1.GetMessage().Length == Constants.OBJECT_ID_STRING_LENGTH)
1576
r.Append("object " + cmd_1.GetMessage() + " missing");
1580
r.Append(cmd_1.GetMessage());
1586
case ReceiveCommand.Result.REJECTED_OTHER_REASON:
1588
if (cmd_1.GetMessage() == null)
1590
r.Append("unspecified reason");
1594
r.Append(cmd_1.GetMessage());
1599
case ReceiveCommand.Result.LOCK_FAILURE:
1601
r.Append("failed to lock");
1605
case ReceiveCommand.Result.OK:
1607
// We shouldn't have reached this case (see 'ok' case above).
1611
@out.SendString(r.ToString());
1615
internal abstract class Reporter
1617
/// <exception cref="System.IO.IOException"></exception>
1618
internal abstract void SendString(string s);
318
protected internal override string GetLockMessageProcessName()
320
return "jgit receive-pack";