| 
						
					 | 
					 | 
					@@ -19,6 +19,7 @@ import (
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						"golang.org/x/net/context"
 | 
					 | 
					 | 
					 | 
						"golang.org/x/net/context"
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						"google.golang.org/grpc"
 | 
					 | 
					 | 
					 | 
						"google.golang.org/grpc"
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						"google.golang.org/grpc/codes"
 | 
					 | 
					 | 
					 | 
						"google.golang.org/grpc/codes"
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						"google.golang.org/grpc/status"
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					)
 | 
					 | 
					 | 
					 | 
					)
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					type service struct {
 | 
					 | 
					 | 
					 | 
					type service struct {
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -68,7 +69,7 @@ func (s *service) Register(server *grpc.Server) error {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					func (s *service) Info(ctx context.Context, req *api.InfoRequest) (*api.InfoResponse, error) {
 | 
					 | 
					 | 
					 | 
					func (s *service) Info(ctx context.Context, req *api.InfoRequest) (*api.InfoResponse, error) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						if err := req.Digest.Validate(); err != nil {
 | 
					 | 
					 | 
					 | 
						if err := req.Digest.Validate(); err != nil {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							return nil, grpc.Errorf(codes.InvalidArgument, "%q failed validation", req.Digest)
 | 
					 | 
					 | 
					 | 
							return nil, status.Errorf(codes.InvalidArgument, "%q failed validation", req.Digest)
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						}
 | 
					 | 
					 | 
					 | 
						}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						bi, err := s.store.Info(ctx, req.Digest)
 | 
					 | 
					 | 
					 | 
						bi, err := s.store.Info(ctx, req.Digest)
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -83,7 +84,7 @@ func (s *service) Info(ctx context.Context, req *api.InfoRequest) (*api.InfoResp
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					func (s *service) Update(ctx context.Context, req *api.UpdateRequest) (*api.UpdateResponse, error) {
 | 
					 | 
					 | 
					 | 
					func (s *service) Update(ctx context.Context, req *api.UpdateRequest) (*api.UpdateResponse, error) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						if err := req.Info.Digest.Validate(); err != nil {
 | 
					 | 
					 | 
					 | 
						if err := req.Info.Digest.Validate(); err != nil {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							return nil, grpc.Errorf(codes.InvalidArgument, "%q failed validation", req.Info.Digest)
 | 
					 | 
					 | 
					 | 
							return nil, status.Errorf(codes.InvalidArgument, "%q failed validation", req.Info.Digest)
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						}
 | 
					 | 
					 | 
					 | 
						}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						info, err := s.store.Update(ctx, infoFromGRPC(req.Info), req.UpdateMask.GetPaths()...)
 | 
					 | 
					 | 
					 | 
						info, err := s.store.Update(ctx, infoFromGRPC(req.Info), req.UpdateMask.GetPaths()...)
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -140,7 +141,7 @@ func (s *service) List(req *api.ListContentRequest, session api.Content_ListServ
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					func (s *service) Delete(ctx context.Context, req *api.DeleteContentRequest) (*ptypes.Empty, error) {
 | 
					 | 
					 | 
					 | 
					func (s *service) Delete(ctx context.Context, req *api.DeleteContentRequest) (*ptypes.Empty, error) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						if err := req.Digest.Validate(); err != nil {
 | 
					 | 
					 | 
					 | 
						if err := req.Digest.Validate(); err != nil {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							return nil, grpc.Errorf(codes.InvalidArgument, err.Error())
 | 
					 | 
					 | 
					 | 
							return nil, status.Errorf(codes.InvalidArgument, err.Error())
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						}
 | 
					 | 
					 | 
					 | 
						}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						if err := s.store.Delete(ctx, req.Digest); err != nil {
 | 
					 | 
					 | 
					 | 
						if err := s.store.Delete(ctx, req.Digest); err != nil {
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -158,7 +159,7 @@ func (s *service) Delete(ctx context.Context, req *api.DeleteContentRequest) (*p
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					func (s *service) Read(req *api.ReadContentRequest, session api.Content_ReadServer) error {
 | 
					 | 
					 | 
					 | 
					func (s *service) Read(req *api.ReadContentRequest, session api.Content_ReadServer) error {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						if err := req.Digest.Validate(); err != nil {
 | 
					 | 
					 | 
					 | 
						if err := req.Digest.Validate(); err != nil {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							return grpc.Errorf(codes.InvalidArgument, "%v: %v", req.Digest, err)
 | 
					 | 
					 | 
					 | 
							return status.Errorf(codes.InvalidArgument, "%v: %v", req.Digest, err)
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						}
 | 
					 | 
					 | 
					 | 
						}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						oi, err := s.store.Info(session.Context(), req.Digest)
 | 
					 | 
					 | 
					 | 
						oi, err := s.store.Info(session.Context(), req.Digest)
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -191,7 +192,7 @@ func (s *service) Read(req *api.ReadContentRequest, session api.Content_ReadServ
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						}
 | 
					 | 
					 | 
					 | 
						}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						if offset+size > oi.Size {
 | 
					 | 
					 | 
					 | 
						if offset+size > oi.Size {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							return grpc.Errorf(codes.OutOfRange, "read past object length %v bytes", oi.Size)
 | 
					 | 
					 | 
					 | 
							return status.Errorf(codes.OutOfRange, "read past object length %v bytes", oi.Size)
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						}
 | 
					 | 
					 | 
					 | 
						}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						if _, err := io.CopyBuffer(
 | 
					 | 
					 | 
					 | 
						if _, err := io.CopyBuffer(
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -277,7 +278,7 @@ func (s *service) Write(session api.Content_WriteServer) (err error) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						defer func(msg *api.WriteContentResponse) {
 | 
					 | 
					 | 
					 | 
						defer func(msg *api.WriteContentResponse) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							// pump through the last message if no error was encountered
 | 
					 | 
					 | 
					 | 
							// pump through the last message if no error was encountered
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							if err != nil {
 | 
					 | 
					 | 
					 | 
							if err != nil {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								if grpc.Code(err) != codes.AlreadyExists {
 | 
					 | 
					 | 
					 | 
								if s, ok := status.FromError(err); ok && s.Code() != codes.AlreadyExists {
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									// TODO(stevvooe): Really need a log line here to track which
 | 
					 | 
					 | 
					 | 
									// TODO(stevvooe): Really need a log line here to track which
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									// errors are actually causing failure on the server side. May want
 | 
					 | 
					 | 
					 | 
									// errors are actually causing failure on the server side. May want
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									// to configure the service with an interceptor to make this work
 | 
					 | 
					 | 
					 | 
									// to configure the service with an interceptor to make this work
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -302,7 +303,7 @@ func (s *service) Write(session api.Content_WriteServer) (err error) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						ref = req.Ref
 | 
					 | 
					 | 
					 | 
						ref = req.Ref
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						if ref == "" {
 | 
					 | 
					 | 
					 | 
						if ref == "" {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							return grpc.Errorf(codes.InvalidArgument, "first message must have a reference")
 | 
					 | 
					 | 
					 | 
							return status.Errorf(codes.InvalidArgument, "first message must have a reference")
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						}
 | 
					 | 
					 | 
					 | 
						}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						fields := logrus.Fields{
 | 
					 | 
					 | 
					 | 
						fields := logrus.Fields{
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -356,7 +357,7 @@ func (s *service) Write(session api.Content_WriteServer) (err error) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							// users use the same writer style for each with a minimum of overhead.
 | 
					 | 
					 | 
					 | 
							// users use the same writer style for each with a minimum of overhead.
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							if req.Expected != "" {
 | 
					 | 
					 | 
					 | 
							if req.Expected != "" {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								if expected != "" && expected != req.Expected {
 | 
					 | 
					 | 
					 | 
								if expected != "" && expected != req.Expected {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									return grpc.Errorf(codes.InvalidArgument, "inconsistent digest provided: %v != %v", req.Expected, expected)
 | 
					 | 
					 | 
					 | 
									return status.Errorf(codes.InvalidArgument, "inconsistent digest provided: %v != %v", req.Expected, expected)
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								}
 | 
					 | 
					 | 
					 | 
								}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								expected = req.Expected
 | 
					 | 
					 | 
					 | 
								expected = req.Expected
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -365,7 +366,7 @@ func (s *service) Write(session api.Content_WriteServer) (err error) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
										log.G(ctx).WithError(err).Error("failed to abort write")
 | 
					 | 
					 | 
					 | 
										log.G(ctx).WithError(err).Error("failed to abort write")
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									}
 | 
					 | 
					 | 
					 | 
									}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									return grpc.Errorf(codes.AlreadyExists, "blob with expected digest %v exists", req.Expected)
 | 
					 | 
					 | 
					 | 
									return status.Errorf(codes.AlreadyExists, "blob with expected digest %v exists", req.Expected)
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								}
 | 
					 | 
					 | 
					 | 
								}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							}
 | 
					 | 
					 | 
					 | 
							}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -373,7 +374,7 @@ func (s *service) Write(session api.Content_WriteServer) (err error) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								// Update the expected total. Typically, this could be seen at
 | 
					 | 
					 | 
					 | 
								// Update the expected total. Typically, this could be seen at
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								// negotiation time or on a commit message.
 | 
					 | 
					 | 
					 | 
								// negotiation time or on a commit message.
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								if total > 0 && req.Total != total {
 | 
					 | 
					 | 
					 | 
								if total > 0 && req.Total != total {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									return grpc.Errorf(codes.InvalidArgument, "inconsistent total provided: %v != %v", req.Total, total)
 | 
					 | 
					 | 
					 | 
									return status.Errorf(codes.InvalidArgument, "inconsistent total provided: %v != %v", req.Total, total)
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								}
 | 
					 | 
					 | 
					 | 
								}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								total = req.Total
 | 
					 | 
					 | 
					 | 
								total = req.Total
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							}
 | 
					 | 
					 | 
					 | 
							}
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -388,7 +389,7 @@ func (s *service) Write(session api.Content_WriteServer) (err error) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								if req.Offset > 0 {
 | 
					 | 
					 | 
					 | 
								if req.Offset > 0 {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									// validate the offset if provided
 | 
					 | 
					 | 
					 | 
									// validate the offset if provided
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									if req.Offset != ws.Offset {
 | 
					 | 
					 | 
					 | 
									if req.Offset != ws.Offset {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
										return grpc.Errorf(codes.OutOfRange, "write @%v must occur at current offset %v", req.Offset, ws.Offset)
 | 
					 | 
					 | 
					 | 
										return status.Errorf(codes.OutOfRange, "write @%v must occur at current offset %v", req.Offset, ws.Offset)
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									}
 | 
					 | 
					 | 
					 | 
									}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								}
 | 
					 | 
					 | 
					 | 
								}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -411,7 +412,7 @@ func (s *service) Write(session api.Content_WriteServer) (err error) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									if n != len(req.Data) {
 | 
					 | 
					 | 
					 | 
									if n != len(req.Data) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
										// TODO(stevvooe): Perhaps, we can recover this by including it
 | 
					 | 
					 | 
					 | 
										// TODO(stevvooe): Perhaps, we can recover this by including it
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
										// in the offset on the write return.
 | 
					 | 
					 | 
					 | 
										// in the offset on the write return.
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
										return grpc.Errorf(codes.DataLoss, "wrote %v of %v bytes", n, len(req.Data))
 | 
					 | 
					 | 
					 | 
										return status.Errorf(codes.DataLoss, "wrote %v of %v bytes", n, len(req.Data))
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									}
 | 
					 | 
					 | 
					 | 
									}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									msg.Offset += int64(n)
 | 
					 | 
					 | 
					 | 
									msg.Offset += int64(n)
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					 
 |