Skip to content

Commit

Permalink
fix #72343
Browse files Browse the repository at this point in the history
  • Loading branch information
bpasero committed Apr 18, 2019
1 parent fe31e7b commit 407e266
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 14 deletions.
5 changes: 5 additions & 0 deletions src/vs/platform/files/common/files.ts
Original file line number Diff line number Diff line change
Expand Up @@ -753,6 +753,11 @@ export enum FileKind {
export const MIN_MAX_MEMORY_SIZE_MB = 2048;
export const FALLBACK_MAX_MEMORY_SIZE_MB = 4096;

/**
* A hint to disable etag checking for reading/writing.
*/
export const ETAG_DISABLED = '';

export function etag(mtime: number, size: number): string;
export function etag(mtime: number | undefined, size: number | undefined): string | undefined;
export function etag(mtime: number | undefined, size: number | undefined): string | undefined {
Expand Down
8 changes: 4 additions & 4 deletions src/vs/workbench/services/files/common/fileService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/

import { Disposable, IDisposable, toDisposable, combinedDisposable, dispose } from 'vs/base/common/lifecycle';
import { IFileService, IResolveFileOptions, FileChangesEvent, FileOperationEvent, IFileSystemProviderRegistrationEvent, IFileSystemProvider, IFileStat, IResolveFileResult, ICreateFileOptions, IFileSystemProviderActivationEvent, FileOperationError, FileOperationResult, FileOperation, FileSystemProviderCapabilities, FileType, toFileSystemProviderErrorCode, FileSystemProviderErrorCode, IStat, IFileStatWithMetadata, IResolveMetadataFileOptions, etag, hasReadWriteCapability, hasFileFolderCopyCapability, hasOpenReadWriteCloseCapability, toFileOperationResult, IFileSystemProviderWithOpenReadWriteCloseCapability, IFileSystemProviderWithFileReadWriteCapability, IResolveFileResultWithMetadata, IWatchOptions, IWriteFileOptions, IReadFileOptions, IFileStreamContent, IFileContent } from 'vs/platform/files/common/files';
import { IFileService, IResolveFileOptions, FileChangesEvent, FileOperationEvent, IFileSystemProviderRegistrationEvent, IFileSystemProvider, IFileStat, IResolveFileResult, ICreateFileOptions, IFileSystemProviderActivationEvent, FileOperationError, FileOperationResult, FileOperation, FileSystemProviderCapabilities, FileType, toFileSystemProviderErrorCode, FileSystemProviderErrorCode, IStat, IFileStatWithMetadata, IResolveMetadataFileOptions, etag, hasReadWriteCapability, hasFileFolderCopyCapability, hasOpenReadWriteCloseCapability, toFileOperationResult, IFileSystemProviderWithOpenReadWriteCloseCapability, IFileSystemProviderWithFileReadWriteCapability, IResolveFileResultWithMetadata, IWatchOptions, IWriteFileOptions, IReadFileOptions, IFileStreamContent, IFileContent, ETAG_DISABLED } from 'vs/platform/files/common/files';
import { URI } from 'vs/base/common/uri';
import { Event, Emitter } from 'vs/base/common/event';
import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
Expand Down Expand Up @@ -337,7 +337,7 @@ export class FileService extends Disposable implements IFileService {
// check for size is a weaker check because it can return a false negative if the file has changed
// but to the same length. This is a compromise we take to avoid having to produce checksums of
// the file content for comparison which would be much slower to compute.
if (options && typeof options.mtime === 'number' && typeof options.etag === 'string' && options.mtime < stat.mtime && options.etag !== etag(stat.size, options.mtime)) {
if (options && typeof options.mtime === 'number' && typeof options.etag === 'string' && options.etag !== ETAG_DISABLED && options.mtime < stat.mtime && options.etag !== etag(stat.size, options.mtime)) {
throw new FileOperationError(localize('fileModifiedError', "File Modified Since"), FileOperationResult.FILE_MODIFIED_SINCE, options);
}

Expand Down Expand Up @@ -375,7 +375,7 @@ export class FileService extends Disposable implements IFileService {
// due to the likelyhood of hitting a NOT_MODIFIED_SINCE result.
// otherwise, we let it run in parallel to the file reading for
// optimal startup performance.
if (options && options.etag) {
if (options && typeof options.etag === 'string' && options.etag !== ETAG_DISABLED) {
await statPromise;
}

Expand Down Expand Up @@ -493,7 +493,7 @@ export class FileService extends Disposable implements IFileService {
}

// Return early if file not modified since
if (options && options.etag && options.etag === stat.etag) {
if (options && options.etag === stat.etag) {
throw new FileOperationError(localize('fileNotModifiedError', "File not modified since"), FileOperationResult.FILE_NOT_MODIFIED_SINCE, options);
}

Expand Down
27 changes: 18 additions & 9 deletions src/vs/workbench/services/textfile/common/textFileEditorModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { ITextFileService, IAutoSaveConfiguration, ModelState, ITextFileEditorMo
import { EncodingMode } from 'vs/workbench/common/editor';
import { BaseTextEditorModel } from 'vs/workbench/common/editor/textEditorModel';
import { IBackupFileService } from 'vs/workbench/services/backup/common/backup';
import { IFileService, FileOperationError, FileOperationResult, CONTENT_CHANGE_EVENT_BUFFER_DELAY, FileChangesEvent, FileChangeType, IFileStatWithMetadata, etag } from 'vs/platform/files/common/files';
import { IFileService, FileOperationError, FileOperationResult, CONTENT_CHANGE_EVENT_BUFFER_DELAY, FileChangesEvent, FileChangeType, IFileStatWithMetadata, ETAG_DISABLED } from 'vs/platform/files/common/files';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IModeService, ILanguageSelection } from 'vs/editor/common/services/modeService';
import { IModelService } from 'vs/editor/common/services/modelService';
Expand Down Expand Up @@ -55,26 +55,35 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
get onDidStateChange(): Event<StateChange> { return this._onDidStateChange.event; }

private resource: URI;

private contentEncoding: string; // encoding as reported from disk
private preferredEncoding: string; // encoding as chosen by the user
private dirty: boolean;

private versionId: number;
private bufferSavedVersionId: number;
private lastResolvedDiskStat: IFileStatWithMetadata;
private blockModelContentChange: boolean;

private createTextEditorModelPromise: Promise<TextFileEditorModel> | null;

private lastResolvedDiskStat: IFileStatWithMetadata;

private autoSaveAfterMillies?: number;
private autoSaveAfterMilliesEnabled: boolean;
private autoSaveDisposable?: IDisposable;
private contentChangeEventScheduler: RunOnceScheduler;
private orphanedChangeEventScheduler: RunOnceScheduler;

private saveSequentializer: SaveSequentializer;
private disposed: boolean;
private lastSaveAttemptTime: number;
private createTextEditorModelPromise: Promise<TextFileEditorModel> | null;

private contentChangeEventScheduler: RunOnceScheduler;
private orphanedChangeEventScheduler: RunOnceScheduler;

private dirty: boolean;
private inConflictMode: boolean;
private inOrphanMode: boolean;
private inErrorMode: boolean;

private disposed: boolean;

constructor(
resource: URI,
preferredEncoding: string,
Expand Down Expand Up @@ -271,8 +280,8 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
name: basename(this.resource),
mtime: Date.now(),
size: 0,
etag: etag(Date.now(), 0),
value: createTextBufferFactory(''), /* will be filled later from backup */
etag: ETAG_DISABLED, // always allow to save content restored from a backup (see https://github.com/Microsoft/vscode/issues/72343)
value: createTextBufferFactory(''), // will be filled later from backup
encoding: this.textFileService.encoding.getPreferredWriteEncoding(this.resource, this.preferredEncoding).encoding,
isReadonly: false
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -510,7 +510,6 @@ export abstract class TextFileService extends Disposable implements ITextFileSer
}));
}


// Soft revert the dirty source files if any
await this.revertAll(dirtySourceModels.map(dirtySourceModel => dirtySourceModel.getResource()), { soft: true });

Expand Down

0 comments on commit 407e266

Please sign in to comment.