@theia/filesystem 1.77.0-next.99 → 1.78.0-next.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/browser/breadcrumbs/filepath-breadcrumb.js +4 -8
- package/lib/browser/breadcrumbs/filepath-breadcrumb.js.map +1 -1
- package/lib/browser/breadcrumbs/filepath-breadcrumbs-container.d.ts +1 -1
- package/lib/browser/breadcrumbs/filepath-breadcrumbs-container.d.ts.map +1 -1
- package/lib/browser/breadcrumbs/filepath-breadcrumbs-container.js +18 -25
- package/lib/browser/breadcrumbs/filepath-breadcrumbs-container.js.map +1 -1
- package/lib/browser/breadcrumbs/filepath-breadcrumbs-contribution.d.ts +5 -5
- package/lib/browser/breadcrumbs/filepath-breadcrumbs-contribution.d.ts.map +1 -1
- package/lib/browser/breadcrumbs/filepath-breadcrumbs-contribution.js +27 -33
- package/lib/browser/breadcrumbs/filepath-breadcrumbs-contribution.js.map +1 -1
- package/lib/browser/download/file-download-command-contribution.d.ts +1 -1
- package/lib/browser/download/file-download-command-contribution.d.ts.map +1 -1
- package/lib/browser/download/file-download-command-contribution.js +28 -33
- package/lib/browser/download/file-download-command-contribution.js.map +1 -1
- package/lib/browser/download/file-download-frontend-module.js +8 -10
- package/lib/browser/download/file-download-frontend-module.js.map +1 -1
- package/lib/browser/download/file-download-service.d.ts +1 -1
- package/lib/browser/download/file-download-service.d.ts.map +1 -1
- package/lib/browser/download/file-download-service.js +19 -24
- package/lib/browser/download/file-download-service.js.map +1 -1
- package/lib/browser/file-dialog/file-dialog-container.d.ts +1 -1
- package/lib/browser/file-dialog/file-dialog-container.d.ts.map +1 -1
- package/lib/browser/file-dialog/file-dialog-container.js +25 -30
- package/lib/browser/file-dialog/file-dialog-container.js.map +1 -1
- package/lib/browser/file-dialog/file-dialog-hidden-files-renderer.d.ts +1 -1
- package/lib/browser/file-dialog/file-dialog-hidden-files-renderer.d.ts.map +1 -1
- package/lib/browser/file-dialog/file-dialog-hidden-files-renderer.js +13 -21
- package/lib/browser/file-dialog/file-dialog-hidden-files-renderer.js.map +1 -1
- package/lib/browser/file-dialog/file-dialog-model.d.ts +2 -2
- package/lib/browser/file-dialog/file-dialog-model.d.ts.map +1 -1
- package/lib/browser/file-dialog/file-dialog-model.js +20 -27
- package/lib/browser/file-dialog/file-dialog-model.js.map +1 -1
- package/lib/browser/file-dialog/file-dialog-module.js +21 -23
- package/lib/browser/file-dialog/file-dialog-module.js.map +1 -1
- package/lib/browser/file-dialog/file-dialog-service.d.ts +4 -4
- package/lib/browser/file-dialog/file-dialog-service.d.ts.map +1 -1
- package/lib/browser/file-dialog/file-dialog-service.js +29 -38
- package/lib/browser/file-dialog/file-dialog-service.js.map +1 -1
- package/lib/browser/file-dialog/file-dialog-tree-filters-renderer.d.ts +1 -1
- package/lib/browser/file-dialog/file-dialog-tree-filters-renderer.d.ts.map +1 -1
- package/lib/browser/file-dialog/file-dialog-tree-filters-renderer.js +16 -21
- package/lib/browser/file-dialog/file-dialog-tree-filters-renderer.js.map +1 -1
- package/lib/browser/file-dialog/file-dialog-tree-filters-renderer.spec.js +9 -11
- package/lib/browser/file-dialog/file-dialog-tree-filters-renderer.spec.js.map +1 -1
- package/lib/browser/file-dialog/file-dialog-tree.d.ts +2 -2
- package/lib/browser/file-dialog/file-dialog-tree.d.ts.map +1 -1
- package/lib/browser/file-dialog/file-dialog-tree.js +8 -11
- package/lib/browser/file-dialog/file-dialog-tree.js.map +1 -1
- package/lib/browser/file-dialog/file-dialog-widget.d.ts +2 -2
- package/lib/browser/file-dialog/file-dialog-widget.d.ts.map +1 -1
- package/lib/browser/file-dialog/file-dialog-widget.js +18 -23
- package/lib/browser/file-dialog/file-dialog-widget.js.map +1 -1
- package/lib/browser/file-dialog/file-dialog.d.ts +6 -6
- package/lib/browser/file-dialog/file-dialog.d.ts.map +1 -1
- package/lib/browser/file-dialog/file-dialog.js +114 -132
- package/lib/browser/file-dialog/file-dialog.js.map +1 -1
- package/lib/browser/file-dialog/index.d.ts +4 -4
- package/lib/browser/file-dialog/index.d.ts.map +1 -1
- package/lib/browser/file-dialog/index.js +4 -7
- package/lib/browser/file-dialog/index.js.map +1 -1
- package/lib/browser/file-resource.d.ts +2 -2
- package/lib/browser/file-resource.d.ts.map +1 -1
- package/lib/browser/file-resource.js +64 -71
- package/lib/browser/file-resource.js.map +1 -1
- package/lib/browser/file-resource.spec.js +39 -42
- package/lib/browser/file-resource.spec.js.map +1 -1
- package/lib/browser/file-selection.d.ts +1 -1
- package/lib/browser/file-selection.d.ts.map +1 -1
- package/lib/browser/file-selection.js +7 -10
- package/lib/browser/file-selection.js.map +1 -1
- package/lib/browser/file-service-activation.spec.js +14 -16
- package/lib/browser/file-service-activation.spec.js.map +1 -1
- package/lib/browser/file-service-copy.spec.js +44 -47
- package/lib/browser/file-service-copy.spec.js.map +1 -1
- package/lib/browser/file-service-watcher.spec.js +199 -202
- package/lib/browser/file-service-watcher.spec.js.map +1 -1
- package/lib/browser/file-service.d.ts +3 -3
- package/lib/browser/file-service.d.ts.map +1 -1
- package/lib/browser/file-service.js +166 -181
- package/lib/browser/file-service.js.map +1 -1
- package/lib/browser/file-tree/file-tree-container.js +12 -15
- package/lib/browser/file-tree/file-tree-container.js.map +1 -1
- package/lib/browser/file-tree/file-tree-decorator-adapter.js +23 -31
- package/lib/browser/file-tree/file-tree-decorator-adapter.js.map +1 -1
- package/lib/browser/file-tree/file-tree-decorator-adapter.spec.js +26 -29
- package/lib/browser/file-tree/file-tree-decorator-adapter.spec.js.map +1 -1
- package/lib/browser/file-tree/file-tree-label-provider.d.ts +1 -1
- package/lib/browser/file-tree/file-tree-label-provider.d.ts.map +1 -1
- package/lib/browser/file-tree/file-tree-label-provider.js +13 -18
- package/lib/browser/file-tree/file-tree-label-provider.js.map +1 -1
- package/lib/browser/file-tree/file-tree-model.d.ts +5 -5
- package/lib/browser/file-tree/file-tree-model.d.ts.map +1 -1
- package/lib/browser/file-tree/file-tree-model.js +48 -52
- package/lib/browser/file-tree/file-tree-model.js.map +1 -1
- package/lib/browser/file-tree/file-tree-widget.d.ts +3 -3
- package/lib/browser/file-tree/file-tree-widget.d.ts.map +1 -1
- package/lib/browser/file-tree/file-tree-widget.js +66 -72
- package/lib/browser/file-tree/file-tree-widget.js.map +1 -1
- package/lib/browser/file-tree/file-tree.d.ts +3 -3
- package/lib/browser/file-tree/file-tree.d.ts.map +1 -1
- package/lib/browser/file-tree/file-tree.js +26 -31
- package/lib/browser/file-tree/file-tree.js.map +1 -1
- package/lib/browser/file-tree/index.d.ts +6 -6
- package/lib/browser/file-tree/index.d.ts.map +1 -1
- package/lib/browser/file-tree/index.js +6 -9
- package/lib/browser/file-tree/index.js.map +1 -1
- package/lib/browser/filesystem-frontend-contribution.d.ts +6 -6
- package/lib/browser/filesystem-frontend-contribution.d.ts.map +1 -1
- package/lib/browser/filesystem-frontend-contribution.js +75 -90
- package/lib/browser/filesystem-frontend-contribution.js.map +1 -1
- package/lib/browser/filesystem-frontend-module.js +47 -50
- package/lib/browser/filesystem-frontend-module.js.map +1 -1
- package/lib/browser/filesystem-saveable-service.d.ts +2 -2
- package/lib/browser/filesystem-saveable-service.d.ts.map +1 -1
- package/lib/browser/filesystem-saveable-service.js +35 -44
- package/lib/browser/filesystem-saveable-service.js.map +1 -1
- package/lib/browser/filesystem-watcher-error-handler.js +13 -18
- package/lib/browser/filesystem-watcher-error-handler.js.map +1 -1
- package/lib/browser/index.d.ts +4 -4
- package/lib/browser/index.d.ts.map +1 -1
- package/lib/browser/index.js +4 -7
- package/lib/browser/index.js.map +1 -1
- package/lib/browser/location/index.d.ts +2 -2
- package/lib/browser/location/index.d.ts.map +1 -1
- package/lib/browser/location/index.js +2 -5
- package/lib/browser/location/index.js.map +1 -1
- package/lib/browser/location/location-renderer.d.ts +3 -3
- package/lib/browser/location/location-renderer.d.ts.map +1 -1
- package/lib/browser/location/location-renderer.js +42 -51
- package/lib/browser/location/location-renderer.js.map +1 -1
- package/lib/browser/location/location-renderer.spec.js +61 -64
- package/lib/browser/location/location-renderer.spec.js.map +1 -1
- package/lib/browser/location/location-service.js +1 -2
- package/lib/browser/location/location-service.js.map +1 -1
- package/lib/browser/remote-file-service-contribution.d.ts +2 -2
- package/lib/browser/remote-file-service-contribution.d.ts.map +1 -1
- package/lib/browser/remote-file-service-contribution.js +8 -12
- package/lib/browser/remote-file-service-contribution.js.map +1 -1
- package/lib/browser/upload/file-upload-service-impl.d.ts +3 -3
- package/lib/browser/upload/file-upload-service-impl.d.ts.map +1 -1
- package/lib/browser/upload/file-upload-service-impl.js +55 -64
- package/lib/browser/upload/file-upload-service-impl.js.map +1 -1
- package/lib/browser/vscode-file-service-contribution.d.ts +2 -2
- package/lib/browser/vscode-file-service-contribution.d.ts.map +1 -1
- package/lib/browser/vscode-file-service-contribution.js +23 -28
- package/lib/browser/vscode-file-service-contribution.js.map +1 -1
- package/lib/browser-only/browser-only-filesystem-frontend-module.js +21 -23
- package/lib/browser-only/browser-only-filesystem-frontend-module.js.map +1 -1
- package/lib/browser-only/browser-only-filesystem-provider-server.d.ts +1 -1
- package/lib/browser-only/browser-only-filesystem-provider-server.d.ts.map +1 -1
- package/lib/browser-only/browser-only-filesystem-provider-server.js +10 -13
- package/lib/browser-only/browser-only-filesystem-provider-server.js.map +1 -1
- package/lib/browser-only/download/file-download-command-contribution.d.ts +1 -1
- package/lib/browser-only/download/file-download-command-contribution.d.ts.map +1 -1
- package/lib/browser-only/download/file-download-command-contribution.js +14 -19
- package/lib/browser-only/download/file-download-command-contribution.js.map +1 -1
- package/lib/browser-only/download/file-download-frontend-module.js +8 -10
- package/lib/browser-only/download/file-download-frontend-module.js.map +1 -1
- package/lib/browser-only/download/file-download-service.d.ts +3 -3
- package/lib/browser-only/download/file-download-service.d.ts.map +1 -1
- package/lib/browser-only/download/file-download-service.js +26 -33
- package/lib/browser-only/download/file-download-service.js.map +1 -1
- package/lib/browser-only/file-search.d.ts.map +1 -1
- package/lib/browser-only/file-search.js +9 -15
- package/lib/browser-only/file-search.js.map +1 -1
- package/lib/browser-only/opfs-filesystem-initialization.d.ts +1 -1
- package/lib/browser-only/opfs-filesystem-initialization.d.ts.map +1 -1
- package/lib/browser-only/opfs-filesystem-initialization.js +6 -9
- package/lib/browser-only/opfs-filesystem-initialization.js.map +1 -1
- package/lib/browser-only/opfs-filesystem-provider.d.ts +2 -2
- package/lib/browser-only/opfs-filesystem-provider.d.ts.map +1 -1
- package/lib/browser-only/opfs-filesystem-provider.js +60 -68
- package/lib/browser-only/opfs-filesystem-provider.js.map +1 -1
- package/lib/browser-only/upload/file-upload-service-impl.d.ts +3 -3
- package/lib/browser-only/upload/file-upload-service-impl.d.ts.map +1 -1
- package/lib/browser-only/upload/file-upload-service-impl.js +51 -60
- package/lib/browser-only/upload/file-upload-service-impl.js.map +1 -1
- package/lib/common/delegating-file-system-provider.d.ts +1 -1
- package/lib/common/delegating-file-system-provider.d.ts.map +1 -1
- package/lib/common/delegating-file-system-provider.js +18 -22
- package/lib/common/delegating-file-system-provider.js.map +1 -1
- package/lib/common/download/file-download.js +5 -8
- package/lib/common/download/file-download.js.map +1 -1
- package/lib/common/file-upload.js +1 -4
- package/lib/common/file-upload.js.map +1 -1
- package/lib/common/files.js +38 -59
- package/lib/common/files.js.map +1 -1
- package/lib/common/files.spec.js +22 -25
- package/lib/common/files.spec.js.map +1 -1
- package/lib/common/filesystem-preferences.js +39 -44
- package/lib/common/filesystem-preferences.js.map +1 -1
- package/lib/common/filesystem-utils.d.ts +1 -1
- package/lib/common/filesystem-utils.d.ts.map +1 -1
- package/lib/common/filesystem-utils.js +2 -5
- package/lib/common/filesystem-utils.js.map +1 -1
- package/lib/common/filesystem-utils.spec.js +227 -229
- package/lib/common/filesystem-utils.spec.js.map +1 -1
- package/lib/common/filesystem-watcher-protocol.d.ts +1 -1
- package/lib/common/filesystem-watcher-protocol.d.ts.map +1 -1
- package/lib/common/filesystem-watcher-protocol.js +2 -5
- package/lib/common/filesystem-watcher-protocol.js.map +1 -1
- package/lib/common/filesystem.js +2 -5
- package/lib/common/filesystem.js.map +1 -1
- package/lib/common/index.d.ts +3 -3
- package/lib/common/index.d.ts.map +1 -1
- package/lib/common/index.js +3 -6
- package/lib/common/index.js.map +1 -1
- package/lib/common/io.d.ts +2 -2
- package/lib/common/io.d.ts.map +1 -1
- package/lib/common/io.js +10 -13
- package/lib/common/io.js.map +1 -1
- package/lib/common/remote-file-system-provider.d.ts +5 -5
- package/lib/common/remote-file-system-provider.d.ts.map +1 -1
- package/lib/common/remote-file-system-provider.js +81 -93
- package/lib/common/remote-file-system-provider.js.map +1 -1
- package/lib/common/upload/file-upload.js +1 -4
- package/lib/common/upload/file-upload.js.map +1 -1
- package/lib/electron-browser/file-dialog/electron-file-dialog-module.js +6 -8
- package/lib/electron-browser/file-dialog/electron-file-dialog-module.js.map +1 -1
- package/lib/electron-browser/file-dialog/electron-file-dialog-service.d.ts +3 -3
- package/lib/electron-browser/file-dialog/electron-file-dialog-service.d.ts.map +1 -1
- package/lib/electron-browser/file-dialog/electron-file-dialog-service.js +21 -23
- package/lib/electron-browser/file-dialog/electron-file-dialog-service.js.map +1 -1
- package/lib/electron-browser/file-dialog/electron-file-dialog-service.spec.js +33 -12
- package/lib/electron-browser/file-dialog/electron-file-dialog-service.spec.js.map +1 -1
- package/lib/electron-browser/preload.js +6 -9
- package/lib/electron-browser/preload.js.map +1 -1
- package/lib/electron-common/electron-api.d.ts +4 -0
- package/lib/electron-common/electron-api.d.ts.map +1 -1
- package/lib/electron-common/electron-api.js +2 -5
- package/lib/electron-common/electron-api.js.map +1 -1
- package/lib/electron-main/electron-api-main.d.ts.map +1 -1
- package/lib/electron-main/electron-api-main.js +19 -18
- package/lib/electron-main/electron-api-main.js.map +1 -1
- package/lib/electron-main/electron-main-module.js +6 -8
- package/lib/electron-main/electron-main-module.js.map +1 -1
- package/lib/node/archive/archive-extractor.d.ts +86 -0
- package/lib/node/archive/archive-extractor.d.ts.map +1 -0
- package/lib/node/archive/archive-extractor.js +290 -0
- package/lib/node/archive/archive-extractor.js.map +1 -0
- package/lib/node/archive/archive-extractor.spec.d.ts +2 -0
- package/lib/node/archive/archive-extractor.spec.d.ts.map +1 -0
- package/lib/node/archive/archive-extractor.spec.js +317 -0
- package/lib/node/archive/archive-extractor.spec.js.map +1 -0
- package/lib/node/archive/test/test-archives.d.ts +20 -0
- package/lib/node/archive/test/test-archives.d.ts.map +1 -0
- package/lib/node/archive/test/test-archives.js +97 -0
- package/lib/node/archive/test/test-archives.js.map +1 -0
- package/lib/node/disk-file-system-provider.d.ts +2 -2
- package/lib/node/disk-file-system-provider.d.ts.map +1 -1
- package/lib/node/disk-file-system-provider.js +111 -119
- package/lib/node/disk-file-system-provider.js.map +1 -1
- package/lib/node/disk-file-system-provider.spec.js +53 -56
- package/lib/node/disk-file-system-provider.spec.js.map +1 -1
- package/lib/node/download/directory-archiver.js +13 -16
- package/lib/node/download/directory-archiver.js.map +1 -1
- package/lib/node/download/directory-archiver.spec.js +20 -23
- package/lib/node/download/directory-archiver.spec.js.map +1 -1
- package/lib/node/download/file-download-backend-module.js +14 -16
- package/lib/node/download/file-download-backend-module.js.map +1 -1
- package/lib/node/download/file-download-cache.js +11 -15
- package/lib/node/download/file-download-cache.js.map +1 -1
- package/lib/node/download/file-download-endpoint.d.ts +1 -1
- package/lib/node/download/file-download-endpoint.d.ts.map +1 -1
- package/lib/node/download/file-download-endpoint.js +25 -31
- package/lib/node/download/file-download-endpoint.js.map +1 -1
- package/lib/node/download/file-download-handler.d.ts +2 -2
- package/lib/node/download/file-download-handler.d.ts.map +1 -1
- package/lib/node/download/file-download-handler.js +70 -76
- package/lib/node/download/file-download-handler.js.map +1 -1
- package/lib/node/download/test/mock-directory-archiver.d.ts +1 -1
- package/lib/node/download/test/mock-directory-archiver.d.ts.map +1 -1
- package/lib/node/download/test/mock-directory-archiver.js +2 -6
- package/lib/node/download/test/mock-directory-archiver.js.map +1 -1
- package/lib/node/file-change-collection.d.ts +1 -1
- package/lib/node/file-change-collection.d.ts.map +1 -1
- package/lib/node/file-change-collection.js +1 -5
- package/lib/node/file-change-collection.js.map +1 -1
- package/lib/node/file-change-collection.spec.js +5 -8
- package/lib/node/file-change-collection.spec.js.map +1 -1
- package/lib/node/filesystem-backend-module.d.ts +1 -1
- package/lib/node/filesystem-backend-module.d.ts.map +1 -1
- package/lib/node/filesystem-backend-module.js +60 -64
- package/lib/node/filesystem-backend-module.js.map +1 -1
- package/lib/node/filesystem-watcher-client.d.ts +2 -2
- package/lib/node/filesystem-watcher-client.d.ts.map +1 -1
- package/lib/node/filesystem-watcher-client.js +11 -16
- package/lib/node/filesystem-watcher-client.js.map +1 -1
- package/lib/node/filesystem-watcher-dispatcher.d.ts +1 -1
- package/lib/node/filesystem-watcher-dispatcher.d.ts.map +1 -1
- package/lib/node/filesystem-watcher-dispatcher.js +9 -13
- package/lib/node/filesystem-watcher-dispatcher.js.map +1 -1
- package/lib/node/filesystem-watcher-service-impl.d.ts +3 -3
- package/lib/node/filesystem-watcher-service-impl.d.ts.map +1 -1
- package/lib/node/filesystem-watcher-service-impl.js +7 -11
- package/lib/node/filesystem-watcher-service-impl.js.map +1 -1
- package/lib/node/filesystem-watcher-service-impl.spec.js +23 -26
- package/lib/node/filesystem-watcher-service-impl.spec.js.map +1 -1
- package/lib/node/filesystem-watcher.d.ts +1 -1
- package/lib/node/filesystem-watcher.d.ts.map +1 -1
- package/lib/node/filesystem-watcher.js +6 -11
- package/lib/node/filesystem-watcher.js.map +1 -1
- package/lib/node/nodejs-watcher/node-directory-watcher.d.ts +4 -4
- package/lib/node/nodejs-watcher/node-directory-watcher.d.ts.map +1 -1
- package/lib/node/nodejs-watcher/node-directory-watcher.js +20 -26
- package/lib/node/nodejs-watcher/node-directory-watcher.js.map +1 -1
- package/lib/node/nodejs-watcher/node-directory-watcher.spec.js +51 -54
- package/lib/node/nodejs-watcher/node-directory-watcher.spec.js.map +1 -1
- package/lib/node/nodejs-watcher/watch-request-router.d.ts +3 -3
- package/lib/node/nodejs-watcher/watch-request-router.d.ts.map +1 -1
- package/lib/node/nodejs-watcher/watch-request-router.js +8 -13
- package/lib/node/nodejs-watcher/watch-request-router.js.map +1 -1
- package/lib/node/nodejs-watcher/watcher-host.d.ts +1 -1
- package/lib/node/nodejs-watcher/watcher-host.d.ts.map +1 -1
- package/lib/node/nodejs-watcher/watcher-host.js +7 -12
- package/lib/node/nodejs-watcher/watcher-host.js.map +1 -1
- package/lib/node/parcel-watcher/index.js +6 -9
- package/lib/node/parcel-watcher/index.js.map +1 -1
- package/lib/node/parcel-watcher/parcel-filesystem-service.d.ts +4 -4
- package/lib/node/parcel-watcher/parcel-filesystem-service.d.ts.map +1 -1
- package/lib/node/parcel-watcher/parcel-filesystem-service.js +4 -8
- package/lib/node/parcel-watcher/parcel-filesystem-service.js.map +1 -1
- package/lib/node/parcel-watcher/parcel-filesystem-watcher.spec.js +23 -26
- package/lib/node/parcel-watcher/parcel-filesystem-watcher.spec.js.map +1 -1
- package/lib/node/parcel-watcher/parcel-options.js +1 -4
- package/lib/node/parcel-watcher/parcel-options.js.map +1 -1
- package/lib/node/parcel-watcher/parcel-watcher-exclude.spec.js +11 -16
- package/lib/node/parcel-watcher/parcel-watcher-exclude.spec.js.map +1 -1
- package/lib/node/parcel-watcher/parcel-watcher-retry.spec.js +11 -16
- package/lib/node/parcel-watcher/parcel-watcher-retry.spec.js.map +1 -1
- package/lib/node/parcel-watcher/parcel-watcher.d.ts +3 -3
- package/lib/node/parcel-watcher/parcel-watcher.d.ts.map +1 -1
- package/lib/node/parcel-watcher/parcel-watcher.js +28 -32
- package/lib/node/parcel-watcher/parcel-watcher.js.map +1 -1
- package/lib/node/test/watcher-test-helper.d.ts +1 -1
- package/lib/node/test/watcher-test-helper.d.ts.map +1 -1
- package/lib/node/test/watcher-test-helper.js +5 -10
- package/lib/node/test/watcher-test-helper.js.map +1 -1
- package/lib/node/upload/node-file-upload-service.d.ts +1 -1
- package/lib/node/upload/node-file-upload-service.d.ts.map +1 -1
- package/lib/node/upload/node-file-upload-service.js +20 -25
- package/lib/node/upload/node-file-upload-service.js.map +1 -1
- package/lib/node/upload/node-file-upload-service.spec.js +21 -24
- package/lib/node/upload/node-file-upload-service.spec.js.map +1 -1
- package/package.json +21 -5
- package/src/browser/breadcrumbs/filepath-breadcrumb.ts +1 -1
- package/src/browser/breadcrumbs/filepath-breadcrumbs-container.ts +1 -1
- package/src/browser/breadcrumbs/filepath-breadcrumbs-contribution.ts +5 -5
- package/src/browser/download/file-download-command-contribution.ts +1 -1
- package/src/browser/download/file-download-frontend-module.ts +3 -3
- package/src/browser/download/file-download-service.ts +1 -1
- package/src/browser/file-dialog/file-dialog-container.ts +5 -5
- package/src/browser/file-dialog/file-dialog-hidden-files-renderer.tsx +1 -1
- package/src/browser/file-dialog/file-dialog-model.ts +2 -2
- package/src/browser/file-dialog/file-dialog-module.ts +5 -5
- package/src/browser/file-dialog/file-dialog-service.ts +4 -4
- package/src/browser/file-dialog/file-dialog-tree-filters-renderer.spec.ts +2 -2
- package/src/browser/file-dialog/file-dialog-tree-filters-renderer.tsx +1 -1
- package/src/browser/file-dialog/file-dialog-tree.ts +2 -2
- package/src/browser/file-dialog/file-dialog-widget.ts +2 -2
- package/src/browser/file-dialog/file-dialog.ts +16 -13
- package/src/browser/file-dialog/index.ts +4 -4
- package/src/browser/file-resource.spec.ts +3 -3
- package/src/browser/file-resource.ts +3 -3
- package/src/browser/file-selection.ts +1 -1
- package/src/browser/file-service-activation.spec.ts +2 -2
- package/src/browser/file-service-copy.spec.ts +2 -2
- package/src/browser/file-service-watcher.spec.ts +2 -2
- package/src/browser/file-service.ts +6 -6
- package/src/browser/file-tree/file-tree-container.ts +3 -3
- package/src/browser/file-tree/file-tree-decorator-adapter.spec.ts +1 -1
- package/src/browser/file-tree/file-tree-decorator-adapter.ts +1 -1
- package/src/browser/file-tree/file-tree-label-provider.ts +1 -1
- package/src/browser/file-tree/file-tree-model.ts +12 -6
- package/src/browser/file-tree/file-tree-widget.tsx +8 -5
- package/src/browser/file-tree/file-tree.ts +3 -3
- package/src/browser/file-tree/index.ts +6 -6
- package/src/browser/filesystem-frontend-contribution.ts +6 -6
- package/src/browser/filesystem-frontend-module.ts +14 -14
- package/src/browser/filesystem-saveable-service.ts +2 -2
- package/src/browser/index.ts +4 -4
- package/src/browser/location/index.ts +2 -2
- package/src/browser/location/location-renderer.spec.ts +3 -3
- package/src/browser/location/location-renderer.tsx +3 -3
- package/src/browser/remote-file-service-contribution.ts +2 -2
- package/src/browser/upload/file-upload-service-impl.ts +5 -5
- package/src/browser/vscode-file-service-contribution.ts +2 -2
- package/src/browser-only/browser-only-filesystem-frontend-module.ts +7 -7
- package/src/browser-only/browser-only-filesystem-provider-server.ts +1 -1
- package/src/browser-only/download/file-download-command-contribution.ts +2 -2
- package/src/browser-only/download/file-download-frontend-module.ts +3 -3
- package/src/browser-only/download/file-download-service.ts +3 -3
- package/src/browser-only/file-search.ts +2 -1
- package/src/browser-only/opfs-filesystem-initialization.ts +1 -1
- package/src/browser-only/opfs-filesystem-provider.ts +3 -3
- package/src/browser-only/upload/file-upload-service-impl.ts +4 -4
- package/src/common/delegating-file-system-provider.ts +1 -1
- package/src/common/files.spec.ts +1 -1
- package/src/common/filesystem-utils.spec.ts +2 -2
- package/src/common/filesystem-utils.ts +1 -1
- package/src/common/filesystem-watcher-protocol.ts +1 -1
- package/src/common/index.ts +3 -3
- package/src/common/io.ts +2 -2
- package/src/common/remote-file-system-provider.ts +1 -1
- package/src/electron-browser/file-dialog/electron-file-dialog-module.ts +2 -2
- package/src/electron-browser/file-dialog/electron-file-dialog-service.spec.ts +30 -3
- package/src/electron-browser/file-dialog/electron-file-dialog-service.ts +8 -6
- package/src/electron-browser/preload.ts +1 -1
- package/src/electron-common/electron-api.ts +4 -0
- package/src/electron-main/electron-api-main.ts +7 -3
- package/src/electron-main/electron-main-module.ts +1 -1
- package/src/node/archive/archive-extractor.spec.ts +359 -0
- package/src/node/archive/archive-extractor.ts +350 -0
- package/src/node/archive/test/test-archives.ts +117 -0
- package/src/node/disk-file-system-provider.spec.ts +3 -3
- package/src/node/disk-file-system-provider.ts +7 -6
- package/src/node/download/directory-archiver.spec.ts +1 -1
- package/src/node/download/file-download-backend-module.ts +4 -4
- package/src/node/download/file-download-endpoint.ts +4 -3
- package/src/node/download/file-download-handler.ts +3 -3
- package/src/node/download/test/mock-directory-archiver.ts +1 -1
- package/src/node/file-change-collection.spec.ts +2 -2
- package/src/node/file-change-collection.ts +1 -1
- package/src/node/filesystem-backend-module.ts +15 -12
- package/src/node/filesystem-watcher-client.ts +2 -2
- package/src/node/filesystem-watcher-dispatcher.ts +1 -1
- package/src/node/filesystem-watcher-service-impl.spec.ts +5 -5
- package/src/node/filesystem-watcher-service-impl.ts +4 -4
- package/src/node/filesystem-watcher.ts +1 -1
- package/src/node/nodejs-watcher/node-directory-watcher.spec.ts +5 -5
- package/src/node/nodejs-watcher/node-directory-watcher.ts +5 -5
- package/src/node/nodejs-watcher/watch-request-router.ts +4 -4
- package/src/node/nodejs-watcher/watcher-host.ts +1 -1
- package/src/node/parcel-watcher/index.ts +2 -2
- package/src/node/parcel-watcher/parcel-filesystem-service.ts +4 -4
- package/src/node/parcel-watcher/parcel-filesystem-watcher.spec.ts +2 -2
- package/src/node/parcel-watcher/parcel-watcher-exclude.spec.ts +4 -8
- package/src/node/parcel-watcher/parcel-watcher-retry.spec.ts +4 -6
- package/src/node/parcel-watcher/parcel-watcher.ts +7 -6
- package/src/node/test/watcher-test-helper.ts +1 -1
- package/src/node/upload/node-file-upload-service.spec.ts +1 -1
- package/src/node/upload/node-file-upload-service.ts +6 -6
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2026 EclipseSource GmbH and others.
|
|
3
|
+
//
|
|
4
|
+
// This program and the accompanying materials are made available under the
|
|
5
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
//
|
|
8
|
+
// This Source Code may also be made available under the following Secondary
|
|
9
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
// with the GNU Classpath Exception which is available at
|
|
12
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
//
|
|
14
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
|
+
// *****************************************************************************
|
|
16
|
+
|
|
17
|
+
import * as fs from 'fs';
|
|
18
|
+
import * as path from 'path';
|
|
19
|
+
import { Readable } from 'stream';
|
|
20
|
+
import { pipeline } from 'stream/promises';
|
|
21
|
+
import { createGunzip } from 'zlib';
|
|
22
|
+
import * as yauzl from 'yauzl';
|
|
23
|
+
import * as tarStream from 'tar-stream';
|
|
24
|
+
import { inject, injectable, named } from '@theia/core/shared/inversify';
|
|
25
|
+
import { ILogger } from '@theia/core/lib/common/logger';
|
|
26
|
+
|
|
27
|
+
export type ArchiveFormat = 'zip' | 'tar' | 'tgz';
|
|
28
|
+
|
|
29
|
+
/** The path of an archive on disk, or the content of an archive. */
|
|
30
|
+
export type ArchiveSource = string | Uint8Array;
|
|
31
|
+
|
|
32
|
+
export interface ArchiveOptions {
|
|
33
|
+
/** The format of the archive. Detected from its content if omitted. */
|
|
34
|
+
format?: ArchiveFormat;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface ArchiveReadOptions extends ArchiveOptions {
|
|
38
|
+
/** Selects the files to read by their path in the archive. All files are read if omitted. */
|
|
39
|
+
filter?: (entryPath: string) => boolean;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface ArchiveEntry {
|
|
43
|
+
/** The path of the entry relative to the root of the archive, using `/` as separator. */
|
|
44
|
+
path: string;
|
|
45
|
+
type: 'file' | 'directory';
|
|
46
|
+
/** The permission bits of the entry, without the setuid, setgid and sticky bits. */
|
|
47
|
+
mode?: number;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface ArchiveFile extends ArchiveEntry {
|
|
51
|
+
type: 'file';
|
|
52
|
+
data: Buffer;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export const ArchiveExtractor = Symbol('ArchiveExtractor');
|
|
56
|
+
/**
|
|
57
|
+
* Extracts zip, tar and gzipped tar archives.
|
|
58
|
+
*
|
|
59
|
+
* Entry paths and links are not trusted: an entry whose path is absolute or leaves the archive root fails the
|
|
60
|
+
* extraction, and links and other special entries are skipped rather than created, so that nothing can be
|
|
61
|
+
* written or exposed outside of the destination. The size of the extracted content is not limited.
|
|
62
|
+
*/
|
|
63
|
+
export interface ArchiveExtractor {
|
|
64
|
+
/**
|
|
65
|
+
* Extracts the archive into the destination directory, creating it if needed.
|
|
66
|
+
* @returns the extracted files and directories.
|
|
67
|
+
*/
|
|
68
|
+
extract(source: ArchiveSource, destination: string, options?: ArchiveOptions): Promise<ArchiveEntry[]>;
|
|
69
|
+
/**
|
|
70
|
+
* Reads the content of the files in the archive without writing anything to disk.
|
|
71
|
+
*/
|
|
72
|
+
readFiles(source: ArchiveSource, options?: ArchiveReadOptions): Promise<ArchiveFile[]>;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** An entry as reported by the reader of an archive format, before its path is validated. */
|
|
76
|
+
interface RawArchiveEntry {
|
|
77
|
+
name: string;
|
|
78
|
+
kind: 'file' | 'directory' | 'unsupported';
|
|
79
|
+
mode?: number;
|
|
80
|
+
/** Opens the content of a file entry. Entries that are not opened are discarded. */
|
|
81
|
+
open(): Promise<Readable>;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
type RawArchiveEntryVisitor = (entry: RawArchiveEntry) => Promise<void>;
|
|
85
|
+
|
|
86
|
+
const S_IFMT = 0o170000;
|
|
87
|
+
const S_IFREG = 0o100000;
|
|
88
|
+
const S_IFDIR = 0o040000;
|
|
89
|
+
const PERMISSION_BITS = 0o777;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Existing links are rejected before a file is opened; `O_NOFOLLOW` additionally guards against a link created in between
|
|
93
|
+
* where the platform supports it, which Windows does not.
|
|
94
|
+
*/
|
|
95
|
+
const WRITE_FLAGS = fs.constants.O_WRONLY | fs.constants.O_CREAT | fs.constants.O_TRUNC | (fs.constants.O_NOFOLLOW ?? 0);
|
|
96
|
+
|
|
97
|
+
@injectable()
|
|
98
|
+
export class ArchiveExtractorImpl implements ArchiveExtractor {
|
|
99
|
+
|
|
100
|
+
/** Not available to instances created without dependency injection, which report skipped entries on the console. */
|
|
101
|
+
@inject(ILogger) @named('filesystem:ArchiveExtractorImpl')
|
|
102
|
+
protected readonly logger?: ILogger;
|
|
103
|
+
|
|
104
|
+
async extract(source: ArchiveSource, destination: string, options: ArchiveOptions = {}): Promise<ArchiveEntry[]> {
|
|
105
|
+
await fs.promises.mkdir(destination, { recursive: true });
|
|
106
|
+
const root = await fs.promises.realpath(destination);
|
|
107
|
+
const verifiedDirectories = new Set<string>([root]);
|
|
108
|
+
const entries: ArchiveEntry[] = [];
|
|
109
|
+
const skipped: string[] = [];
|
|
110
|
+
await this.readEntries(source, options.format, async entry => {
|
|
111
|
+
const entryPath = this.toEntryPath(entry.name);
|
|
112
|
+
if (!entryPath) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
if (entry.kind === 'unsupported') {
|
|
116
|
+
skipped.push(entryPath);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
const target = path.join(root, ...entryPath.split('/'));
|
|
120
|
+
if (entry.kind === 'directory') {
|
|
121
|
+
await this.createDirectory(root, target, verifiedDirectories);
|
|
122
|
+
entries.push({ path: entryPath, type: 'directory', mode: entry.mode });
|
|
123
|
+
} else {
|
|
124
|
+
await this.createDirectory(root, path.dirname(target), verifiedDirectories);
|
|
125
|
+
await this.assertNoLink(root, target);
|
|
126
|
+
await this.writeFile(target, await entry.open(), entry.mode);
|
|
127
|
+
entries.push({ path: entryPath, type: 'file', mode: entry.mode });
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
this.reportSkipped(source, skipped);
|
|
131
|
+
return entries;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async readFiles(source: ArchiveSource, options: ArchiveReadOptions = {}): Promise<ArchiveFile[]> {
|
|
135
|
+
const files: ArchiveFile[] = [];
|
|
136
|
+
const skipped: string[] = [];
|
|
137
|
+
await this.readEntries(source, options.format, async entry => {
|
|
138
|
+
const entryPath = this.toEntryPath(entry.name);
|
|
139
|
+
if (entryPath && entry.kind === 'unsupported') {
|
|
140
|
+
skipped.push(entryPath);
|
|
141
|
+
}
|
|
142
|
+
if (!entryPath || entry.kind !== 'file' || (options.filter && !options.filter(entryPath))) {
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
const chunks: Buffer[] = [];
|
|
146
|
+
for await (const chunk of await entry.open()) {
|
|
147
|
+
chunks.push(chunk);
|
|
148
|
+
}
|
|
149
|
+
files.push({ path: entryPath, type: 'file', mode: entry.mode, data: Buffer.concat(chunks) });
|
|
150
|
+
});
|
|
151
|
+
this.reportSkipped(source, skipped);
|
|
152
|
+
return files;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
protected async readEntries(source: ArchiveSource, format: ArchiveFormat | undefined, visit: RawArchiveEntryVisitor): Promise<void> {
|
|
156
|
+
switch (format ?? await this.detectFormat(source)) {
|
|
157
|
+
case 'zip':
|
|
158
|
+
return this.readZipEntries(source, visit);
|
|
159
|
+
case 'tar':
|
|
160
|
+
return this.readTarEntries(source, false, visit);
|
|
161
|
+
case 'tgz':
|
|
162
|
+
return this.readTarEntries(source, true, visit);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Detects the format of an archive from its first bytes.
|
|
168
|
+
*/
|
|
169
|
+
protected async detectFormat(source: ArchiveSource): Promise<ArchiveFormat> {
|
|
170
|
+
const header = await this.readHeader(source, 512);
|
|
171
|
+
if (header.length >= 4 && header[0] === 0x50 && header[1] === 0x4b && ((header[2] === 0x03 && header[3] === 0x04) || (header[2] === 0x05 && header[3] === 0x06))) {
|
|
172
|
+
return 'zip';
|
|
173
|
+
}
|
|
174
|
+
if (header.length >= 2 && header[0] === 0x1f && header[1] === 0x8b) {
|
|
175
|
+
return 'tgz';
|
|
176
|
+
}
|
|
177
|
+
if (header.length >= 262 && header.toString('latin1', 257, 262) === 'ustar') {
|
|
178
|
+
return 'tar';
|
|
179
|
+
}
|
|
180
|
+
throw new Error(`Unsupported archive format${typeof source === 'string' ? `: ${source}` : ''}`);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
protected async readHeader(source: ArchiveSource, length: number): Promise<Buffer> {
|
|
184
|
+
if (typeof source !== 'string') {
|
|
185
|
+
return Buffer.from(source.subarray(0, length));
|
|
186
|
+
}
|
|
187
|
+
const handle = await fs.promises.open(source, 'r');
|
|
188
|
+
try {
|
|
189
|
+
const buffer = Buffer.alloc(length);
|
|
190
|
+
const { bytesRead } = await handle.read(buffer, 0, length, 0);
|
|
191
|
+
return buffer.subarray(0, bytesRead);
|
|
192
|
+
} finally {
|
|
193
|
+
await handle.close();
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
protected async readZipEntries(source: ArchiveSource, visit: RawArchiveEntryVisitor): Promise<void> {
|
|
198
|
+
const zipFile = typeof source === 'string'
|
|
199
|
+
? await yauzl.openPromise(source)
|
|
200
|
+
: await yauzl.fromBufferPromise(Buffer.from(source));
|
|
201
|
+
try {
|
|
202
|
+
for await (const entry of zipFile.eachEntry()) {
|
|
203
|
+
// The upper 16 bits hold the Unix mode if the archive was created on a Unix system, and are 0 otherwise.
|
|
204
|
+
const unixMode = entry.externalFileAttributes >>> 16;
|
|
205
|
+
const fileType = unixMode & S_IFMT;
|
|
206
|
+
let kind: RawArchiveEntry['kind'];
|
|
207
|
+
if (entry.fileName.endsWith('/') || fileType === S_IFDIR) {
|
|
208
|
+
kind = 'directory';
|
|
209
|
+
} else if (fileType === 0 || fileType === S_IFREG) {
|
|
210
|
+
kind = 'file';
|
|
211
|
+
} else {
|
|
212
|
+
kind = 'unsupported';
|
|
213
|
+
}
|
|
214
|
+
await visit({
|
|
215
|
+
name: entry.fileName,
|
|
216
|
+
kind,
|
|
217
|
+
mode: this.toMode(unixMode),
|
|
218
|
+
open: () => zipFile.openReadStreamPromise(entry)
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
} finally {
|
|
222
|
+
if (zipFile.isOpen) {
|
|
223
|
+
zipFile.close();
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
protected async readTarEntries(source: ArchiveSource, gzipped: boolean, visit: RawArchiveEntryVisitor): Promise<void> {
|
|
229
|
+
const input = typeof source === 'string' ? fs.createReadStream(source) : Readable.from([Buffer.from(source)]);
|
|
230
|
+
const extract = tarStream.extract();
|
|
231
|
+
const streams: NodeJS.ReadWriteStream[] = gzipped ? [createGunzip()] : [];
|
|
232
|
+
// Resolves with the error instead of rejecting, so that a failure is not unhandled while entries are visited.
|
|
233
|
+
const feeding = pipeline([input, ...streams, extract as unknown as NodeJS.WritableStream]).then(() => undefined, (reason: unknown) => reason);
|
|
234
|
+
try {
|
|
235
|
+
for await (const entry of extract) {
|
|
236
|
+
const header = entry.header;
|
|
237
|
+
let kind: RawArchiveEntry['kind'];
|
|
238
|
+
if (header.type === 'file' || header.type === 'contiguous-file') {
|
|
239
|
+
kind = 'file';
|
|
240
|
+
} else if (header.type === 'directory') {
|
|
241
|
+
kind = 'directory';
|
|
242
|
+
} else {
|
|
243
|
+
kind = 'unsupported';
|
|
244
|
+
}
|
|
245
|
+
let consumed = false;
|
|
246
|
+
await visit({
|
|
247
|
+
name: header.name,
|
|
248
|
+
kind,
|
|
249
|
+
mode: this.toMode(header.mode),
|
|
250
|
+
open: async () => {
|
|
251
|
+
consumed = true;
|
|
252
|
+
// Entries are not Node streams: Node's `pipeline` would wait forever for an entry that a failing archive
|
|
253
|
+
// already destroyed, while a stream created from the entry fails.
|
|
254
|
+
return Readable.from(entry);
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
if (!consumed) {
|
|
258
|
+
entry.resume();
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
} catch (error) {
|
|
262
|
+
input.destroy();
|
|
263
|
+
await feeding;
|
|
264
|
+
throw error;
|
|
265
|
+
}
|
|
266
|
+
const feedError = await feeding;
|
|
267
|
+
if (feedError) {
|
|
268
|
+
throw feedError;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Normalizes the name of an entry to a relative path with `/` as separator.
|
|
274
|
+
* @returns `undefined` for the archive root.
|
|
275
|
+
* @throws if the name is absolute or leaves the archive root.
|
|
276
|
+
*/
|
|
277
|
+
protected toEntryPath(name: string): string | undefined {
|
|
278
|
+
const normalized = name.replace(/\\/g, '/');
|
|
279
|
+
if (normalized.startsWith('/') || /^[a-zA-Z]:/.test(normalized)) {
|
|
280
|
+
throw new Error(`Archive entry has an absolute path: ${name}`);
|
|
281
|
+
}
|
|
282
|
+
const segments = normalized.split('/').filter(segment => segment && segment !== '.');
|
|
283
|
+
if (segments.includes('..')) {
|
|
284
|
+
throw new Error(`Archive entry leaves the extraction directory: ${name}`);
|
|
285
|
+
}
|
|
286
|
+
return segments.length > 0 ? segments.join('/') : undefined;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
protected toMode(mode: number | undefined): number | undefined {
|
|
290
|
+
const permissions = (mode ?? 0) & PERMISSION_BITS;
|
|
291
|
+
return permissions || undefined;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Creates a directory below the root one segment at a time and refuses to descend into an existing entry that is not
|
|
296
|
+
* a directory, so that nothing is created or written through a link that already existed in the destination.
|
|
297
|
+
*/
|
|
298
|
+
protected async createDirectory(root: string, directory: string, verifiedDirectories: Set<string>): Promise<void> {
|
|
299
|
+
let current = root;
|
|
300
|
+
for (const segment of path.relative(root, directory).split(path.sep)) {
|
|
301
|
+
current = path.join(current, segment);
|
|
302
|
+
if (verifiedDirectories.has(current)) {
|
|
303
|
+
continue;
|
|
304
|
+
}
|
|
305
|
+
try {
|
|
306
|
+
await fs.promises.mkdir(current);
|
|
307
|
+
} catch (error) {
|
|
308
|
+
if ((error as NodeJS.ErrnoException).code !== 'EEXIST') {
|
|
309
|
+
throw error;
|
|
310
|
+
}
|
|
311
|
+
if (!(await fs.promises.lstat(current)).isDirectory()) {
|
|
312
|
+
throw new Error(`Archive entry leaves the extraction directory: ${path.relative(root, current)}`);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
verifiedDirectories.add(current);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Rejects writing a file over an existing link or special file, which could point outside of the destination.
|
|
321
|
+
*/
|
|
322
|
+
protected async assertNoLink(root: string, target: string): Promise<void> {
|
|
323
|
+
const existing = await fs.promises.lstat(target).catch((error: NodeJS.ErrnoException) => {
|
|
324
|
+
if (error.code === 'ENOENT') {
|
|
325
|
+
return undefined;
|
|
326
|
+
}
|
|
327
|
+
throw error;
|
|
328
|
+
});
|
|
329
|
+
if (existing && !existing.isFile()) {
|
|
330
|
+
throw new Error(`Archive entry would be written through a link or special file: ${path.relative(root, target)}`);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
protected async writeFile(target: string, content: Readable, mode: number | undefined): Promise<void> {
|
|
335
|
+
const handle = await fs.promises.open(target, WRITE_FLAGS, mode ?? 0o666);
|
|
336
|
+
await pipeline(content, handle.createWriteStream());
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
protected reportSkipped(source: ArchiveSource, skipped: string[]): void {
|
|
340
|
+
if (skipped.length > 0) {
|
|
341
|
+
const message = `Skipped ${skipped.length} link or special entries of archive${typeof source === 'string' ? ` ${source}` : ''}: ${skipped.join(', ')}`;
|
|
342
|
+
if (this.logger) {
|
|
343
|
+
this.logger.warn(message);
|
|
344
|
+
} else {
|
|
345
|
+
// eslint-disable-next-line @theia/named-logger-check
|
|
346
|
+
console.warn(message);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2026 EclipseSource GmbH and others.
|
|
3
|
+
//
|
|
4
|
+
// This program and the accompanying materials are made available under the
|
|
5
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
//
|
|
8
|
+
// This Source Code may also be made available under the following Secondary
|
|
9
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
// with the GNU Classpath Exception which is available at
|
|
12
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
//
|
|
14
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
|
+
// *****************************************************************************
|
|
16
|
+
|
|
17
|
+
import { crc32, gzipSync } from 'zlib';
|
|
18
|
+
import * as tarStream from 'tar-stream';
|
|
19
|
+
|
|
20
|
+
export interface TestZipEntry {
|
|
21
|
+
name: string;
|
|
22
|
+
/** The Unix mode including the file type bits, e.g. `0o100644` for a file or `0o120777` for a symlink. */
|
|
23
|
+
mode?: number;
|
|
24
|
+
data?: string | Uint8Array;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Builds a zip archive with stored entries. Unlike archiving libraries, it writes names and modes as given,
|
|
29
|
+
* so that it can produce the hostile archives the extractor has to handle.
|
|
30
|
+
*/
|
|
31
|
+
export function createTestZip(entries: TestZipEntry[]): Buffer {
|
|
32
|
+
const localParts: Buffer[] = [];
|
|
33
|
+
const centralParts: Buffer[] = [];
|
|
34
|
+
let offset = 0;
|
|
35
|
+
for (const entry of entries) {
|
|
36
|
+
const name = Buffer.from(entry.name, 'utf8');
|
|
37
|
+
const data = typeof entry.data === 'string' || entry.data === undefined ? Buffer.from(entry.data ?? '', 'utf8') : Buffer.from(entry.data);
|
|
38
|
+
const checksum = crc32(data);
|
|
39
|
+
|
|
40
|
+
const local = Buffer.alloc(30);
|
|
41
|
+
local.writeUInt32LE(0x04034b50, 0);
|
|
42
|
+
local.writeUInt16LE(20, 4);
|
|
43
|
+
local.writeUInt16LE(0x0800, 6);
|
|
44
|
+
local.writeUInt16LE(0, 8);
|
|
45
|
+
local.writeUInt16LE(0, 10);
|
|
46
|
+
local.writeUInt16LE(0x21, 12);
|
|
47
|
+
local.writeUInt32LE(checksum, 14);
|
|
48
|
+
local.writeUInt32LE(data.length, 18);
|
|
49
|
+
local.writeUInt32LE(data.length, 22);
|
|
50
|
+
local.writeUInt16LE(name.length, 26);
|
|
51
|
+
local.writeUInt16LE(0, 28);
|
|
52
|
+
localParts.push(local, name, data);
|
|
53
|
+
|
|
54
|
+
const central = Buffer.alloc(46);
|
|
55
|
+
central.writeUInt32LE(0x02014b50, 0);
|
|
56
|
+
// Made by Unix, so that the upper 16 bits of the external attributes hold the mode.
|
|
57
|
+
central.writeUInt16LE((3 << 8) | 20, 4);
|
|
58
|
+
central.writeUInt16LE(20, 6);
|
|
59
|
+
central.writeUInt16LE(0x0800, 8);
|
|
60
|
+
central.writeUInt16LE(0, 10);
|
|
61
|
+
central.writeUInt16LE(0, 12);
|
|
62
|
+
central.writeUInt16LE(0x21, 14);
|
|
63
|
+
central.writeUInt32LE(checksum, 16);
|
|
64
|
+
central.writeUInt32LE(data.length, 20);
|
|
65
|
+
central.writeUInt32LE(data.length, 24);
|
|
66
|
+
central.writeUInt16LE(name.length, 28);
|
|
67
|
+
central.writeUInt16LE(0, 30);
|
|
68
|
+
central.writeUInt16LE(0, 32);
|
|
69
|
+
central.writeUInt16LE(0, 34);
|
|
70
|
+
central.writeUInt16LE(0, 36);
|
|
71
|
+
central.writeUInt32LE(((entry.mode ?? 0o100644) << 16) >>> 0, 38);
|
|
72
|
+
central.writeUInt32LE(offset, 42);
|
|
73
|
+
centralParts.push(central, name);
|
|
74
|
+
|
|
75
|
+
offset += local.length + name.length + data.length;
|
|
76
|
+
}
|
|
77
|
+
const centralDirectory = Buffer.concat(centralParts);
|
|
78
|
+
const end = Buffer.alloc(22);
|
|
79
|
+
end.writeUInt32LE(0x06054b50, 0);
|
|
80
|
+
end.writeUInt16LE(0, 4);
|
|
81
|
+
end.writeUInt16LE(0, 6);
|
|
82
|
+
end.writeUInt16LE(entries.length, 8);
|
|
83
|
+
end.writeUInt16LE(entries.length, 10);
|
|
84
|
+
end.writeUInt32LE(centralDirectory.length, 12);
|
|
85
|
+
end.writeUInt32LE(offset, 16);
|
|
86
|
+
end.writeUInt16LE(0, 20);
|
|
87
|
+
return Buffer.concat([...localParts, centralDirectory, end]);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export interface TestTarEntry {
|
|
91
|
+
name: string;
|
|
92
|
+
type?: 'file' | 'directory' | 'symlink' | 'link' | 'fifo';
|
|
93
|
+
mode?: number;
|
|
94
|
+
linkname?: string;
|
|
95
|
+
data?: string | Uint8Array;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export async function createTestTar(entries: TestTarEntry[], gzip = false): Promise<Buffer> {
|
|
99
|
+
const pack = tarStream.pack();
|
|
100
|
+
const chunks: Buffer[] = [];
|
|
101
|
+
const collected = (async () => {
|
|
102
|
+
for await (const chunk of pack) {
|
|
103
|
+
chunks.push(chunk as Buffer);
|
|
104
|
+
}
|
|
105
|
+
})();
|
|
106
|
+
for (const entry of entries) {
|
|
107
|
+
const type = entry.type ?? 'file';
|
|
108
|
+
await new Promise<void>((resolve, reject) => {
|
|
109
|
+
const header = { name: entry.name, type, mode: entry.mode, linkname: entry.linkname };
|
|
110
|
+
pack.entry(header, entry.data ?? '', error => error ? reject(error) : resolve());
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
pack.finalize();
|
|
114
|
+
await collected;
|
|
115
|
+
const tar = Buffer.concat(chunks);
|
|
116
|
+
return gzip ? gzipSync(tar) : tar;
|
|
117
|
+
}
|
|
@@ -27,9 +27,9 @@ import * as os from 'os';
|
|
|
27
27
|
import { join } from 'path';
|
|
28
28
|
import * as temp from 'temp';
|
|
29
29
|
import { generateUuid } from '@theia/core/lib/common/uuid';
|
|
30
|
-
import { FilePermission, FileSystemProviderCapabilities, FileSystemProviderError, FileSystemProviderErrorCode } from '../common/files';
|
|
31
|
-
import { DiskFileSystemProvider } from './disk-file-system-provider';
|
|
32
|
-
import { bindFileSystemWatcherServer } from './filesystem-backend-module';
|
|
30
|
+
import { FilePermission, FileSystemProviderCapabilities, FileSystemProviderError, FileSystemProviderErrorCode } from '../common/files.js';
|
|
31
|
+
import { DiskFileSystemProvider } from './disk-file-system-provider.js';
|
|
32
|
+
import { bindFileSystemWatcherServer } from './filesystem-backend-module.js';
|
|
33
33
|
|
|
34
34
|
const tracked = temp.track();
|
|
35
35
|
|
|
@@ -56,17 +56,18 @@ import {
|
|
|
56
56
|
FileChange,
|
|
57
57
|
WatchOptions,
|
|
58
58
|
FileUpdateOptions, FileUpdateResult, FileReadStreamOptions, FilePermission
|
|
59
|
-
} from '../common/files';
|
|
60
|
-
import { FileSystemWatcherServer } from '../common/filesystem-watcher-protocol';
|
|
61
|
-
import trash
|
|
59
|
+
} from '../common/files.js';
|
|
60
|
+
import { FileSystemWatcherServer } from '../common/filesystem-watcher-protocol.js';
|
|
61
|
+
import trash from 'trash';
|
|
62
62
|
import { TextDocumentContentChangeEvent } from '@theia/core/shared/vscode-languageserver-protocol';
|
|
63
63
|
import { TextDocument } from 'vscode-languageserver-textdocument';
|
|
64
64
|
import { EncodingService } from '@theia/core/lib/common/encoding-service';
|
|
65
65
|
import { BinaryBuffer } from '@theia/core/lib/common/buffer';
|
|
66
66
|
import { ReadableStreamEvents, newWriteableStream } from '@theia/core/lib/common/stream';
|
|
67
67
|
import { CancellationToken } from '@theia/core/lib/common/cancellation';
|
|
68
|
-
import { readFileIntoStream } from '../common/io';
|
|
69
|
-
|
|
68
|
+
import { readFileIntoStream } from '../common/io.js';
|
|
69
|
+
// A CommonJS module whose exports cannot be detected statically, so it is imported as a whole.
|
|
70
|
+
import statMode from 'stat-mode';
|
|
70
71
|
|
|
71
72
|
export namespace DiskFileSystemProvider {
|
|
72
73
|
export interface StatAndLink {
|
|
@@ -156,7 +157,7 @@ export class DiskFileSystemProvider implements Disposable,
|
|
|
156
157
|
async stat(resource: URI): Promise<Stat> {
|
|
157
158
|
try {
|
|
158
159
|
const { stat, symbolicLink } = await this.statLink(this.toFilePath(resource)); // cannot use fs.stat() here to support links properly
|
|
159
|
-
const mode = new Mode(stat);
|
|
160
|
+
const mode = new statMode.Mode(stat);
|
|
160
161
|
return {
|
|
161
162
|
type: this.toType(stat, symbolicLink),
|
|
162
163
|
ctime: stat.birthtime.getTime(), // intentionally not using ctime here, we want the creation time
|
|
@@ -20,7 +20,7 @@ import * as temp from 'temp';
|
|
|
20
20
|
import { extract } from 'tar-fs';
|
|
21
21
|
import { expect } from 'chai';
|
|
22
22
|
import URI from '@theia/core/lib/common/uri';
|
|
23
|
-
import { MockDirectoryArchiver } from './test/mock-directory-archiver';
|
|
23
|
+
import { MockDirectoryArchiver } from './test/mock-directory-archiver.js';
|
|
24
24
|
import { FileUri } from '@theia/core/lib/common/file-uri';
|
|
25
25
|
|
|
26
26
|
const track = temp.track();
|
|
@@ -16,10 +16,10 @@
|
|
|
16
16
|
|
|
17
17
|
import { ContainerModule } from '@theia/core/shared/inversify';
|
|
18
18
|
import { BackendApplicationContribution } from '@theia/core/lib/node/backend-application';
|
|
19
|
-
import { FileDownloadEndpoint } from './file-download-endpoint';
|
|
20
|
-
import { FileDownloadHandler, SingleFileDownloadHandler, MultiFileDownloadHandler, DownloadLinkHandler } from './file-download-handler';
|
|
21
|
-
import { DirectoryArchiver } from './directory-archiver';
|
|
22
|
-
import { FileDownloadCache } from './file-download-cache';
|
|
19
|
+
import { FileDownloadEndpoint } from './file-download-endpoint.js';
|
|
20
|
+
import { FileDownloadHandler, SingleFileDownloadHandler, MultiFileDownloadHandler, DownloadLinkHandler } from './file-download-handler.js';
|
|
21
|
+
import { DirectoryArchiver } from './directory-archiver.js';
|
|
22
|
+
import { FileDownloadCache } from './file-download-cache.js';
|
|
23
23
|
|
|
24
24
|
export default new ContainerModule(bind => {
|
|
25
25
|
bind(FileDownloadEndpoint).toSelf().inSingletonScope();
|
|
@@ -17,12 +17,13 @@
|
|
|
17
17
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
18
18
|
|
|
19
19
|
import { injectable, inject, named } from '@theia/core/shared/inversify';
|
|
20
|
-
|
|
20
|
+
// A CommonJS module whose exports cannot be detected statically, so it is imported as a whole.
|
|
21
|
+
import bodyParser from 'body-parser';
|
|
21
22
|
import { Application, Router, RequestHandler } from '@theia/core/shared/express';
|
|
22
23
|
import { BackendApplicationContribution } from '@theia/core/lib/node/backend-application';
|
|
23
24
|
import { HttpConnectionValidator } from '@theia/core/lib/node';
|
|
24
25
|
import { FileUri } from '@theia/core/lib/common/file-uri';
|
|
25
|
-
import { FileDownloadHandler } from './file-download-handler';
|
|
26
|
+
import { FileDownloadHandler } from './file-download-handler.js';
|
|
26
27
|
|
|
27
28
|
@injectable()
|
|
28
29
|
export class FileDownloadEndpoint implements BackendApplicationContribution {
|
|
@@ -52,7 +53,7 @@ export class FileDownloadEndpoint implements BackendApplicationContribution {
|
|
|
52
53
|
router.get('/', (request, response) => this.singleFileDownloadHandler.handle(request, response));
|
|
53
54
|
router.put('/', (request, response) => this.multiFileDownloadHandler.handle(request, response));
|
|
54
55
|
// Content-Type: application/json
|
|
55
|
-
app.use(json());
|
|
56
|
+
app.use(bodyParser.json());
|
|
56
57
|
app.use(FileDownloadEndpoint.PATH, guard, router);
|
|
57
58
|
app.get('/file', guard, (request, response) => {
|
|
58
59
|
const uri = new URL(request.url, 'http://localhost').search.slice(1);
|
|
@@ -25,9 +25,9 @@ import URI from '@theia/core/lib/common/uri';
|
|
|
25
25
|
import { isEmpty } from '@theia/core/lib/common/objects';
|
|
26
26
|
import { ILogger } from '@theia/core/lib/common/logger';
|
|
27
27
|
import { FileUri } from '@theia/core/lib/common/file-uri';
|
|
28
|
-
import { DirectoryArchiver } from './directory-archiver';
|
|
29
|
-
import { FileDownloadData } from '../../common/download/file-download';
|
|
30
|
-
import { FileDownloadCache, DownloadStorageItem } from './file-download-cache';
|
|
28
|
+
import { DirectoryArchiver } from './directory-archiver.js';
|
|
29
|
+
import { FileDownloadData } from '../../common/download/file-download.js';
|
|
30
|
+
import { FileDownloadCache, DownloadStorageItem } from './file-download-cache.js';
|
|
31
31
|
|
|
32
32
|
interface PrepareDownloadOptions {
|
|
33
33
|
filePath: string;
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
15
|
// *****************************************************************************
|
|
16
16
|
|
|
17
|
-
import { DirectoryArchiver } from '../directory-archiver';
|
|
17
|
+
import { DirectoryArchiver } from '../directory-archiver.js';
|
|
18
18
|
import URI from '@theia/core/lib/common/uri';
|
|
19
19
|
|
|
20
20
|
export class MockDirectoryArchiver extends DirectoryArchiver {
|
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
|
|
17
17
|
import * as assert from 'assert';
|
|
18
18
|
import { FileUri } from '@theia/core/lib/common/file-uri';
|
|
19
|
-
import { FileChangeCollection } from './file-change-collection';
|
|
20
|
-
import { FileChangeType } from '../common/files';
|
|
19
|
+
import { FileChangeCollection } from './file-change-collection.js';
|
|
20
|
+
import { FileChangeType } from '../common/files.js';
|
|
21
21
|
|
|
22
22
|
describe('FileChangeCollection', () => {
|
|
23
23
|
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
15
|
// *****************************************************************************
|
|
16
16
|
|
|
17
|
-
import { FileChange, FileChangeType } from '../common/filesystem-watcher-protocol';
|
|
17
|
+
import { FileChange, FileChangeType } from '../common/filesystem-watcher-protocol.js';
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
20
|
* A file change collection guarantees that only one change is reported for each URI.
|