Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit21eb5a7

Browse files
authored
Merge pull request#1136 from streamich/copilot/fix-1135
feat: implement statfsSync and statfs functions for in-memory filesystem
2 parents57dbc9d +1a5dfbe commit21eb5a7

File tree

7 files changed

+467
-438
lines changed

7 files changed

+467
-438
lines changed

‎src/node/StatFs.ts‎

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import{Superblock}from'../core';
2+
importtype{IStatFs}from'./types/misc';
3+
4+
exporttypeTStatNumber=number|bigint;
5+
6+
/**
7+
* Statistics about a file system, like `fs.StatFs`.
8+
*/
9+
exportclassStatFs<T=TStatNumber>implementsIStatFs<T>{
10+
staticbuild(superblock:Superblock,bigint:false):StatFs<number>;
11+
staticbuild(superblock:Superblock,bigint:true):StatFs<bigint>;
12+
staticbuild(superblock:Superblock,bigint?:boolean):StatFs<TStatNumber>;
13+
staticbuild(superblock:Superblock,bigint:boolean=false):StatFs<TStatNumber>{
14+
conststatfs=newStatFs<TStatNumber>();
15+
16+
constgetStatNumber=!bigint ?number=>number :number=>BigInt(number);
17+
18+
// For in-memory filesystem, provide mock but reasonable values
19+
// Magic number for in-memory filesystem type (similar to ramfs)
20+
statfs.type=getStatNumber(0x858458f6);
21+
22+
// Optimal transfer block size - commonly 4096 bytes
23+
statfs.bsize=getStatNumber(4096);
24+
25+
// Calculate filesystem stats based on current state
26+
consttotalInodes=Object.keys(superblock.inodes).length;
27+
28+
// Mock large filesystem capacity (appears as a large filesystem to applications)
29+
consttotalBlocks=1000000;
30+
constusedBlocks=Math.min(totalInodes*2,totalBlocks);// Rough estimation
31+
constfreeBlocks=totalBlocks-usedBlocks;
32+
33+
statfs.blocks=getStatNumber(totalBlocks);// Total data blocks
34+
statfs.bfree=getStatNumber(freeBlocks);// Free blocks in file system
35+
statfs.bavail=getStatNumber(freeBlocks);// Free blocks available to unprivileged users
36+
37+
// File node statistics
38+
constmaxFiles=1000000;// Mock large number of available inodes
39+
statfs.files=getStatNumber(maxFiles);// Total file nodes in file system
40+
statfs.ffree=getStatNumber(maxFiles-totalInodes);// Free file nodes
41+
42+
returnstatfs;
43+
}
44+
45+
type:T;
46+
bsize:T;
47+
blocks:T;
48+
bfree:T;
49+
bavail:T;
50+
files:T;
51+
ffree:T;
52+
}
53+
54+
exportdefaultStatFs;

‎src/node/__tests__/missing-apis.test.ts‎

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -20,24 +20,4 @@ describe('Missing APIs', () => {
2020
awaitexpect(vol.promises.glob('*.js')).rejects.toThrow('Not implemented');
2121
});
2222
});
23-
24-
describe('openAsBlob API',()=>{
25-
it('should throw "Not implemented"',()=>{
26-
expect(()=>vol.openAsBlob('/test/file.txt')).toThrow('Not implemented');
27-
});
28-
});
29-
30-
describe('statfs APIs',()=>{
31-
it('statfsSync should throw "Not implemented"',()=>{
32-
expect(()=>vol.statfsSync('/test')).toThrow('Not implemented');
33-
});
34-
35-
it('statfs should throw "Not implemented"',()=>{
36-
expect(()=>vol.statfs('/test',()=>{})).toThrow('Not implemented');
37-
});
38-
39-
it('promises.statfs should throw "Not implemented"',async()=>{
40-
awaitexpect(vol.promises.statfs('/test')).rejects.toThrow('Not implemented');
41-
});
42-
});
4323
});

‎src/node/__tests__/statfs.spec.ts‎

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import{Volume}from'../volume';
2+
importStatFsfrom'../StatFs';
3+
4+
describe('statfs API',()=>{
5+
describe('.statfsSync(path)',()=>{
6+
constvol=newVolume();
7+
vol.mkdirSync('/test');
8+
vol.writeFileSync('/test/file.txt','hello world');
9+
10+
it('Returns StatFs instance',()=>{
11+
conststatfs=vol.statfsSync('/test');
12+
expect(statfs).toBeInstanceOf(StatFs);
13+
});
14+
15+
it('Returns filesystem statistics',()=>{
16+
conststatfs=vol.statfsSync('/');
17+
expect(typeofstatfs.type).toBe('number');
18+
expect(typeofstatfs.bsize).toBe('number');
19+
expect(typeofstatfs.blocks).toBe('number');
20+
expect(typeofstatfs.bfree).toBe('number');
21+
expect(typeofstatfs.bavail).toBe('number');
22+
expect(typeofstatfs.files).toBe('number');
23+
expect(typeofstatfs.ffree).toBe('number');
24+
25+
expect(statfs.bsize).toBeGreaterThan(0);
26+
expect(statfs.blocks).toBeGreaterThan(0);
27+
expect(statfs.files).toBeGreaterThan(0);
28+
});
29+
30+
it('Works with bigint option',()=>{
31+
conststatfs=vol.statfsSync('/',{bigint:true});
32+
expect(typeofstatfs.type).toBe('bigint');
33+
expect(typeofstatfs.bsize).toBe('bigint');
34+
expect(typeofstatfs.blocks).toBe('bigint');
35+
expect(typeofstatfs.bfree).toBe('bigint');
36+
expect(typeofstatfs.bavail).toBe('bigint');
37+
expect(typeofstatfs.files).toBe('bigint');
38+
expect(typeofstatfs.ffree).toBe('bigint');
39+
});
40+
41+
it('Throws when path does not exist',()=>{
42+
expect(()=>vol.statfsSync('/nonexistent')).toThrow();
43+
});
44+
45+
it('Works with different paths in same filesystem',()=>{
46+
conststatfs1=vol.statfsSync('/');
47+
conststatfs2=vol.statfsSync('/test');
48+
49+
// Should return same filesystem stats for any path
50+
expect(statfs1.type).toBe(statfs2.type);
51+
expect(statfs1.bsize).toBe(statfs2.bsize);
52+
expect(statfs1.blocks).toBe(statfs2.blocks);
53+
});
54+
});
55+
56+
describe('.statfs(path, callback)',()=>{
57+
constvol=newVolume();
58+
vol.mkdirSync('/test');
59+
vol.writeFileSync('/test/file.txt','hello world');
60+
61+
it('Calls callback with StatFs instance',done=>{
62+
vol.statfs('/test',(err,statfs)=>{
63+
expect(err).toBeNull();
64+
expect(statfs).toBeInstanceOf(StatFs);
65+
expect(statfs).toBeDefined();
66+
expect(typeofstatfs!.type).toBe('number');
67+
expect(statfs!.bsize).toBeGreaterThan(0);
68+
done();
69+
});
70+
});
71+
72+
it('Works with bigint option',done=>{
73+
vol.statfs('/',{bigint:true},(err,statfs)=>{
74+
expect(err).toBeNull();
75+
expect(statfs).toBeDefined();
76+
expect(typeofstatfs!.type).toBe('bigint');
77+
expect(typeofstatfs!.bsize).toBe('bigint');
78+
done();
79+
});
80+
});
81+
82+
it('Calls callback with error when path does not exist',done=>{
83+
vol.statfs('/nonexistent',(err,statfs)=>{
84+
expect(err).toBeTruthy();
85+
expect(err).toBeDefined();
86+
expect(err!.code).toBe('ENOENT');
87+
expect(statfs).toBeUndefined();
88+
done();
89+
});
90+
});
91+
});
92+
});

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1097,6 +1097,7 @@ describe('volume', () => {
10971097
describe('.fstat(fd, callback)',()=>{
10981098
xit('...',()=>{});
10991099
});
1100+
11001101
describe('.linkSync(existingPath, newPath)',()=>{
11011102
constvol=newVolume();
11021103
it('Create a new link',()=>{

‎src/node/options.ts‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,19 @@ export const getStatOptsAndCb: (
108108
)=>[opts.IStatOptions,misc.TCallback<misc.IStats>]=(options,callback?)=>
109109
typeofoptions==='function' ?[getStatOptions(),options] :[getStatOptions(options),validateCallback(callback)];
110110

111+
conststatfsDefaults:opts.IStafsOptions={
112+
bigint:false,
113+
};
114+
exportconstgetStatfsOptions:(options?:any)=>opts.IStafsOptions=(options={})=>
115+
Object.assign({},statfsDefaults,options);
116+
exportconstgetStatfsOptsAndCb:(
117+
options:any,
118+
callback?:misc.TCallback<misc.IStatFs>,
119+
)=>[opts.IStafsOptions,misc.TCallback<misc.IStatFs>]=(options,callback?)=>
120+
typeofoptions==='function'
121+
?[getStatfsOptions(),options]
122+
:[getStatfsOptions(options),validateCallback(callback)];
123+
111124
constrealpathDefaults:opts.IReadFileOptions=optsDefaults;
112125
exportconstgetRealpathOptions=optsGenerator<opts.IRealpathOptions>(realpathDefaults);
113126
exportconstgetRealpathOptsAndCb=optsAndCbGenerator<opts.IRealpathOptions,misc.TDataOut>(getRealpathOptions);

‎src/node/volume.ts‎

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import * as pathModule from 'path';
22
import{Link,Superblock}from'../core';
33
importStatsfrom'./Stats';
44
importDirentfrom'./Dirent';
5+
importStatFsfrom'./StatFs';
56
import{Buffer,bufferAllocUnsafe,bufferFrom}from'../internal/buffer';
67
importqueueMicrotaskfrom'../queueMicrotask';
78
importsetTimeoutUnref,{TSetTimeout}from'../setTimeoutUnref';
@@ -32,6 +33,8 @@ import {
3233
getAppendFileOpts,
3334
getStatOptsAndCb,
3435
getStatOptions,
36+
getStatfsOptsAndCb,
37+
getStatfsOptions,
3538
getRealpathOptsAndCb,
3639
getRealpathOptions,
3740
getWriteFileOptions,
@@ -1442,10 +1445,30 @@ export class Volume implements FsCallbackApi, FsSynchronousApi {
14421445
this.wrapAsync(this._cp,[srcFilename,destFilename,opts_],callback);
14431446
};
14441447

1445-
/**@todo Implement statfs */
1446-
publicstatfsSync:FsSynchronousApi['statfsSync']=notImplemented;
1447-
/**@todo Implement statfs */
1448-
publicstatfs:FsCallbackApi['statfs']=notImplemented;
1448+
private_statfs(filename:string):StatFs<number>;
1449+
private_statfs(filename:string,bigint:false):StatFs<number>;
1450+
private_statfs(filename:string,bigint:true):StatFs<bigint>;
1451+
private_statfs(filename:string,bigint=false):StatFs{
1452+
// Verify the path exists to match Node.js behavior
1453+
this._core.getResolvedLinkOrThrow(filename,'statfs');
1454+
returnStatFs.build(this._core,bigint);
1455+
}
1456+
1457+
statfsSync(path:PathLike):StatFs<number>;
1458+
statfsSync(path:PathLike,options:{bigint:false}):StatFs<number>;
1459+
statfsSync(path:PathLike,options:{bigint:true}):StatFs<bigint>;
1460+
statfsSync(path:PathLike,options?:opts.IStafsOptions):StatFs{
1461+
const{ bigint=false}=getStatfsOptions(options);
1462+
returnthis._statfs(pathToFilename(path),bigintasany);
1463+
}
1464+
1465+
statfs(path:PathLike,callback:misc.TCallback<StatFs>):void;
1466+
statfs(path:PathLike,options:opts.IStafsOptions,callback:misc.TCallback<StatFs>):void;
1467+
statfs(path:PathLike,a:misc.TCallback<StatFs>|opts.IStafsOptions,b?:misc.TCallback<StatFs>):void{
1468+
const[{ bigint=false},callback]=getStatfsOptsAndCb(a,b);
1469+
this.wrapAsync(this._statfs,[pathToFilename(path),bigint],callback);
1470+
}
1471+
14491472
publicopenAsBlob=async(path:PathLike,options?:opts.IOpenAsBlobOptions):Promise<Blob>=>{
14501473
constfilename=pathToFilename(path);
14511474
constlink=this._core.getResolvedLinkOrThrow(filename,'open');

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp