Skip to content
This repository was archived by the owner on Dec 15, 2022. It is now read-only.

Commit bf2deab

Browse files
authored
Merge pull request #331 from gosukiwi/master
Allow to save hidden files in Windows
2 parents 46db2b0 + 802dd37 commit bf2deab

File tree

3 files changed

+49
-6
lines changed

3 files changed

+49
-6
lines changed

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@
5555
"pathwatcher": "^8.1.0",
5656
"serializable": "^1.0.3",
5757
"superstring": "^2.4.2",
58-
"underscore-plus": "^1.0.0"
58+
"underscore-plus": "^1.0.0",
59+
"winattr": "^3.0.0"
5960
},
6061
"standard": {
6162
"env": {

spec/text-buffer-io-spec.js

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const TextBuffer = require('../src/text-buffer')
99
const {TextBuffer: NativeTextBuffer} = require('superstring')
1010
const fsAdmin = require('fs-admin')
1111
const pathwatcher = require('pathwatcher')
12+
const winattr = require('winattr')
1213

1314
process.on('unhandledRejection', console.error)
1415

@@ -447,7 +448,7 @@ describe('TextBuffer IO', () => {
447448
})
448449
})
449450

450-
describe('when a permission error occurs', () => {
451+
describe('when a permission error occurs (not Windows)', () => {
451452
if (process.platform === 'win32') return
452453

453454
beforeEach(() => {
@@ -493,6 +494,21 @@ describe('TextBuffer IO', () => {
493494
})
494495
})
495496
})
497+
498+
describe('when a permission error occurs (Windows)', () => {
499+
if (process.platform !== 'win32') return
500+
501+
it('can bypass hidden files', async done => {
502+
winattr.setSync(filePath, { hidden: true })
503+
504+
buffer.setText('I just wrote to a hidden file in Windows!')
505+
await buffer.save()
506+
507+
expect(fs.readFileSync(filePath, 'utf8')).toBe('I just wrote to a hidden file in Windows!')
508+
expect(winattr.getSync(filePath).hidden).toBe(true)
509+
done()
510+
})
511+
})
496512
})
497513

498514
describe('.saveAs', () => {

src/text-buffer.js

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1927,16 +1927,28 @@ class TextBuffer {
19271927
try {
19281928
await this.buffer.save(destination, this.getEncoding())
19291929
} catch (error) {
1930-
const canEscalate = process.platform === 'darwin' || process.platform === 'linux'
1931-
if (error.code === 'EACCES' && destination === filePath && canEscalate) {
1930+
if (error.code !== 'EACCES' || destination !== filePath) throw error
1931+
1932+
const isWindows = process.platform === 'win32'
1933+
if (isWindows) {
1934+
const winattr = getPromisifiedWinattr()
1935+
const attrs = await winattr.get(filePath)
1936+
if (!attrs.hidden) throw error
1937+
1938+
try {
1939+
await winattr.set(filePath, { hidden: false })
1940+
await this.buffer.save(filePath, this.getEncoding())
1941+
await winattr.set(filePath, { hidden: true })
1942+
} catch (_) {
1943+
throw error
1944+
}
1945+
} else {
19321946
const fsAdmin = require('fs-admin')
19331947
try {
19341948
await this.buffer.save(fsAdmin.createWriteStream(filePath), this.getEncoding())
19351949
} catch (_) {
19361950
throw error
19371951
}
1938-
} else {
1939-
throw error
19401952
}
19411953
}
19421954
} finally {
@@ -2601,4 +2613,18 @@ class SearchCallbackArgument {
26012613
}
26022614
}
26032615

2616+
let _winattr = null
2617+
const getPromisifiedWinattr = function () {
2618+
if (_winattr === null) {
2619+
const { promisify } = require('util')
2620+
const winattr = require('winattr')
2621+
_winattr = {
2622+
set: promisify(winattr.set),
2623+
get: promisify(winattr.get)
2624+
}
2625+
}
2626+
2627+
return _winattr
2628+
}
2629+
26042630
module.exports = TextBuffer

0 commit comments

Comments
 (0)