// Called by AzureBlobSyncProvider.UpdateItem to help with writing item updates
        internal SyncedBlobAttributes UpdateFile(string oldName, FileData fileData, string relativePath, Stream dataStream,
            DateTime expectedLastModified)
        {
            var blob = Container.GetBlobReference(oldName);
            try {
                blob.FetchAttributes();
            }
            catch (StorageClientException e) {
                // Someone may have deleted the blob in the mean time
                if (e.ErrorCode == StorageErrorCode.BlobNotFound) {
                    throw new ApplicationException("Concurrency Violation", e);
                }
                throw;
            }
            var blobProperties = blob.Properties;

            //
            // For directories create an empty data stream
            //
            if (dataStream == null) {
                dataStream = new MemoryStream();
            }

            SetupMetadata(blob.Metadata, fileData, relativePath);
            blobProperties.ContentType = LookupMimeType(Path.GetExtension(fileData.Name));

            // Specify an optimistic concurrency check to prevent races with other endpoints syncing at the same time.
            var opts = new BlobRequestOptions();
            opts.AccessCondition = AccessCondition.IfNotModifiedSince(expectedLastModified);

            try {
                blob.UploadFromStream(dataStream, opts);
            }
            catch (StorageClientException e) {
                // Someone must have modified the file in the mean time
                if (e.ErrorCode == StorageErrorCode.BlobNotFound || e.ErrorCode == StorageErrorCode.ConditionFailed) {
                    throw new ApplicationException("Storage Error", e);
                }
                throw;
            }

            blobProperties = blob.Properties;
            var attributes = new SyncedBlobAttributes(blob.Uri.ToString(), blobProperties.LastModifiedUtc);

            return attributes;
        }
        // Called by AzureBlobSyncProvider.InsertItem.
        internal SyncedBlobAttributes InsertFile(FileData fileData, string relativePath, Stream dataStream)
        {
            if (fileData.Name.Length > MaxFileNameLength) {
                throw new ApplicationException("Name Too Long");
            }

            var blob = Container.GetBlobReference(fileData.RelativePath);
            var blobProperties = blob.Properties;
            var uninitTime = blobProperties.LastModifiedUtc;
            SetupMetadata(blob.Metadata, fileData, relativePath);
            blobProperties.ContentType = LookupMimeType(Path.GetExtension(fileData.Name));

            if (fileData.IsDirectory) {
                // Directories have no stream
                dataStream = new MemoryStream();
            }

            // Specify an optimistic concurrency check to prevent races with other endpoints syncing at the same time.
            var opts = new BlobRequestOptions();
            opts.AccessCondition = AccessCondition.IfNotModifiedSince(uninitTime);

            try {
                blob.UploadFromStream(dataStream, opts);
            }
            catch (StorageException e) {
                if (e.ErrorCode == StorageErrorCode.BlobAlreadyExists || e.ErrorCode == StorageErrorCode.ConditionFailed) {
                    throw new ApplicationException("Concurrency Violation", e);
                }
                throw;
            }

            blobProperties = blob.Properties;
            var attributes = new SyncedBlobAttributes(blob.Uri.ToString(), blobProperties.LastModifiedUtc);

            return attributes;
        }