Skip to content

Commit bccc0b0

Browse files
authored
Merge pull request #1176 from streamich/copilot/fix-1175
fix: correct permission check logic for readonly files in copyFile operations
2 parents dc5cac7 + a06bb4d commit bccc0b0

File tree

3 files changed

+33
-2
lines changed

3 files changed

+33
-2
lines changed

src/core/Superblock.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -444,12 +444,14 @@ export class Superblock {
444444
}
445445

446446
// Check node permissions
447-
if (!(flagsNum & O_WRONLY)) {
447+
// For read access: check if flags are O_RDONLY or O_RDWR (i.e., not only O_WRONLY)
448+
if ((flagsNum & (O_RDONLY | O_RDWR | O_WRONLY)) !== O_WRONLY) {
448449
if (!node.canRead()) {
449450
throw createError(ERROR_CODE.EACCES, 'open', link.getPath());
450451
}
451452
}
452-
if (!(flagsNum & O_RDONLY)) {
453+
// For write access: check if flags are O_WRONLY or O_RDWR
454+
if (flagsNum & (O_WRONLY | O_RDWR)) {
453455
if (!node.canWrite()) {
454456
throw createError(ERROR_CODE.EACCES, 'open', link.getPath());
455457
}

src/node/__tests__/volume/copyFile.test.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,23 @@ describe('copyFile(src, dest[, flags], callback)', () => {
9999
});
100100
});
101101

102+
it('copying readonly source file should succeed', done => {
103+
const vol = create({ '/foo': 'hello world' });
104+
vol.chmodSync('/foo', 0o400); // read-only for owner
105+
106+
// This should not throw - we can read the file even though it's read-only
107+
vol.copyFile('/foo', '/bar', err => {
108+
try {
109+
expect(err).toBeNull();
110+
expect(vol.readFileSync('/foo', 'utf8')).toBe('hello world');
111+
expect(vol.readFileSync('/bar', 'utf8')).toBe('hello world');
112+
done();
113+
} catch (failure) {
114+
done(failure);
115+
}
116+
});
117+
});
118+
102119
it('copying gives EACCES with insufficient permissions on an intermediate directory', done => {
103120
const vol = create({ '/foo/test': 'test' });
104121
vol.mkdirSync('/bar');

src/node/__tests__/volume/copyFileSync.test.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,18 @@ describe('copyFileSync(src, dest[, flags])', () => {
125125
}).toThrowError(/EACCES/);
126126
});
127127
});
128+
129+
it('copying readonly source file should succeed', () => {
130+
const vol = create({ '/foo': 'hello world' });
131+
vol.chmodSync('/foo', 0o400); // read-only for owner
132+
133+
// This should not throw - we can read the file even though it's read-only
134+
vol.copyFileSync('/foo', '/bar');
135+
136+
expect(vol.readFileSync('/foo', 'utf8')).toBe('hello world');
137+
expect(vol.readFileSync('/bar', 'utf8')).toBe('hello world');
138+
});
139+
128140
it('copying throws EACCES with insufficient permissions an intermediate directory', () => {
129141
const vol = create({ '/foo/test': 'test' });
130142
vol.mkdirSync('/bar');

0 commit comments

Comments
 (0)