Skip to content

Commit 1d13e06

Browse files
authored
Fs: use bigint version of file stats, fixes #366 #365 (#367)
Note: only the ino & dev are used as bigint, other numeric inputs are converted as Numbers so there may be other limitations (length for eg.). But changing length to bigint would require lots more work so this should be done in another PR.
1 parent d30736c commit 1d13e06

File tree

6 files changed

+61
-60
lines changed

6 files changed

+61
-60
lines changed

src/services/Fs.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ export function registerFs(fs: Fs): void {
1616
}
1717

1818
export interface FileID {
19-
ino: number
20-
dev: number
19+
ino: bigint
20+
dev: bigint
2121
}
2222

2323
export interface FileDescriptor {
@@ -71,7 +71,7 @@ export const ExeMaskUser = 0o0100
7171

7272
export type FileType = 'exe' | 'img' | 'arc' | 'snd' | 'vid' | 'doc' | 'cod' | ''
7373

74-
export function MakeId(stats: { ino: number; dev: number }): FileID {
74+
export function MakeId(stats: { ino: bigint; dev: bigint }): FileID {
7575
return {
7676
ino: stats.ino,
7777
dev: stats.dev,

src/services/__tests__/Fs.test.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import { MakeId, ExeMaskAll, ExeMaskGroup, ExeMaskUser, filetype, sameID, FileID
55
describe('makeId', () => {
66
it('should return FileID from stats', () => {
77
const stats = {
8-
ino: 123,
9-
dev: 456,
8+
ino: 123n,
9+
dev: 456n,
1010
fullname: 'foo',
1111
}
1212

@@ -19,13 +19,13 @@ describe('makeId', () => {
1919

2020
describe('sameID', () => {
2121
const id1: FileID = {
22-
dev: 10,
23-
ino: 5,
22+
dev: 10n,
23+
ino: 5n,
2424
}
2525

2626
const id2: FileID = {
27-
dev: 28,
28-
ino: 32,
27+
dev: 28n,
28+
ino: 32n,
2929
}
3030

3131
it('should return true if ino & dev are identical', () => {

src/services/__tests__/FsSort.test.ts

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ const files: Array<FileDescriptor> = [
1515
isDir: true,
1616
readonly: false,
1717
id: {
18-
ino: 0,
19-
dev: 1,
18+
ino: 0n,
19+
dev: 1n,
2020
},
2121
isSym: false,
2222
target: '',
@@ -35,8 +35,8 @@ const files: Array<FileDescriptor> = [
3535
isDir: false,
3636
readonly: false,
3737
id: {
38-
ino: 1,
39-
dev: 1,
38+
ino: 1n,
39+
dev: 1n,
4040
},
4141
isSym: false,
4242
target: '',
@@ -55,8 +55,8 @@ const files: Array<FileDescriptor> = [
5555
isDir: false,
5656
readonly: false,
5757
id: {
58-
ino: 2,
59-
dev: 1,
58+
ino: 2n,
59+
dev: 1n,
6060
},
6161
isSym: false,
6262
target: '',
@@ -75,8 +75,8 @@ const files: Array<FileDescriptor> = [
7575
isDir: false,
7676
readonly: false,
7777
id: {
78-
ino: 3,
79-
dev: 1,
78+
ino: 3n,
79+
dev: 1n,
8080
},
8181
isSym: false,
8282
target: '',
@@ -88,24 +88,24 @@ describe('sorting methods', () => {
8888
it('sort by Name/Asc', () => {
8989
const sortMethod = getSortMethod('name', 'asc')
9090
const sorted_ids = files.sort(sortMethod).map((file) => file.id.ino)
91-
expect(sorted_ids).toEqual([2, 0, 1, 3])
91+
expect(sorted_ids).toEqual([2n, 0n, 1n, 3n])
9292
})
9393

9494
it('sort by Name/Desc', () => {
9595
const sortMethod = getSortMethod('name', 'desc')
9696
const sorted_ids = files.sort(sortMethod).map((file) => file.id.ino)
97-
expect(sorted_ids).toEqual([3, 1, 0, 2])
97+
expect(sorted_ids).toEqual([3n, 1n, 0n, 2n])
9898
})
9999

100100
it('sort by Size/Asc', () => {
101101
const sortMethod = getSortMethod('size', 'asc')
102102
const sorted_ids = files.sort(sortMethod).map((file) => file.id.ino)
103-
expect(sorted_ids).toEqual([1, 0, 3, 2])
103+
expect(sorted_ids).toEqual([1n, 0n, 3n, 2n])
104104
})
105105

106106
it('sort by Size/Asc', () => {
107107
const sortMethod = getSortMethod('size', 'desc')
108108
const sorted_ids = files.sort(sortMethod).map((file) => file.id.ino)
109-
expect(sorted_ids).toEqual([2, 3, 0, 1])
109+
expect(sorted_ids).toEqual([2n, 3n, 0n, 1n])
110110
})
111111
})

src/services/plugins/FsFtp.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -231,8 +231,8 @@ class Client {
231231
isSym: false,
232232
target: null,
233233
id: {
234-
ino: mDate.getTime(),
235-
dev: new Date().getTime(),
234+
ino: BigInt(mDate.getTime()),
235+
dev: BigInt(new Date().getTime()),
236236
},
237237
}
238238
return file

src/services/plugins/FsLocal.ts

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -187,8 +187,8 @@ export class LocalApi implements FsApi {
187187
}
188188

189189
async isDir(path: string, transferId = -1): Promise<boolean> {
190-
const lstat = fs.lstatSync(path)
191-
const stat = fs.statSync(path)
190+
const lstat = fs.lstatSync(path, { bigint: true })
191+
const stat = fs.statSync(path, { bigint: true })
192192
return stat.isDirectory() || lstat.isDirectory()
193193
}
194194

@@ -208,7 +208,7 @@ export class LocalApi implements FsApi {
208208
async stat(fullPath: string, transferId = -1): Promise<FileDescriptor> {
209209
try {
210210
const format = path.parse(fullPath)
211-
const stats = fs.lstatSync(fullPath)
211+
const stats = fs.lstatSync(fullPath, { bigint: true })
212212
const file: FileDescriptor = {
213213
dir: format.dir,
214214
fullname: format.base,
@@ -217,12 +217,13 @@ export class LocalApi implements FsApi {
217217
cDate: stats.ctime,
218218
mDate: stats.mtime,
219219
bDate: stats.birthtime,
220-
length: stats.size,
221-
mode: stats.mode,
220+
length: Number(stats.size),
221+
mode: Number(stats.mode),
222222
isDir: stats.isDirectory(),
223223
readonly: false,
224224
type:
225-
(!stats.isDirectory() && filetype(stats.mode, stats.gid, stats.uid, format.ext.toLowerCase())) ||
225+
(!stats.isDirectory() &&
226+
filetype(Number(stats.mode), Number(stats.gid), Number(stats.uid), format.ext.toLowerCase())) ||
226227
'',
227228
isSym: stats.isSymbolicLink(),
228229
target: (stats.isSymbolicLink() && fs.readlinkSync(fullPath)) || null,
@@ -289,16 +290,16 @@ export class LocalApi implements FsApi {
289290
static fileFromPath(fullPath: string): FileDescriptor {
290291
const format = path.parse(fullPath)
291292
let name = fullPath
292-
let stats: Partial<fs.Stats> = null
293+
let stats: Partial<fs.BigIntStats> = null
293294
let targetStats = null
294295

295296
try {
296297
// do not follow symlinks first
297-
stats = fs.lstatSync(fullPath)
298+
stats = fs.lstatSync(fullPath, { bigint: true })
298299
if (stats.isSymbolicLink()) {
299300
// get link target path first
300301
name = fs.readlinkSync(fullPath)
301-
targetStats = fs.statSync(fullPath)
302+
targetStats = fs.statSync(fullPath, { bigint: true })
302303
}
303304
} catch (err) {
304305
console.warn('error getting stats for', fullPath, err)
@@ -310,12 +311,12 @@ export class LocalApi implements FsApi {
310311
ctime: new Date(),
311312
mtime: new Date(),
312313
birthtime: new Date(),
313-
size: stats ? stats.size : 0,
314+
size: stats ? stats.size : 0n,
314315
isDirectory: (): boolean => isDir,
315-
mode: -1,
316+
mode: -1n,
316317
isSymbolicLink: (): boolean => isSymLink,
317-
ino: 0,
318-
dev: 0,
318+
ino: 0n,
319+
dev: 0n,
319320
}
320321
}
321322

@@ -330,12 +331,13 @@ export class LocalApi implements FsApi {
330331
cDate: stats.ctime,
331332
mDate: stats.mtime,
332333
bDate: stats.birthtime,
333-
length: stats.size,
334-
mode: mode,
334+
length: Number(stats.size),
335+
mode: Number(mode),
335336
isDir: targetStats ? targetStats.isDirectory() : stats.isDirectory(),
336337
readonly: false,
337338
type:
338-
(!(targetStats ? targetStats.isDirectory() : stats.isDirectory()) && filetype(mode, 0, 0, extension)) ||
339+
(!(targetStats ? targetStats.isDirectory() : stats.isDirectory()) &&
340+
filetype(Number(mode), 0, 0, extension)) ||
339341
'',
340342
isSym: stats.isSymbolicLink(),
341343
target: (stats.isSymbolicLink() && name) || null,

src/services/plugins/FsVirtual.ts

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
11
/* eslint-disable @typescript-eslint/no-unused-vars */
22
import { fs, vol } from 'memfs'
3-
import type { Stats, ReadStream } from 'fs'
3+
import type { ReadStream, BigIntStats } from 'fs'
44
import { Transform, TransformCallback } from 'stream'
55
import * as path from 'path'
6-
// import mkdir = require('mkdirp')
7-
// import del = require('del')
86

97
import { FsApi, FileDescriptor, Credentials, Fs, filetype, MakeId } from '$src/services/Fs'
10-
// import { size } from '$src/utils/size'
118
import { throttle } from '$src/utils/throttle'
129
import { isWin, HOME_DIR } from '$src/utils/platform'
1310
import { VirtualWatch } from '$src/services/plugins/VirtualWatch'
@@ -191,8 +188,8 @@ export class VirtualApi implements FsApi {
191188
}
192189

193190
async isDir(path: string, transferId = -1): Promise<boolean> {
194-
const lstat = vol.lstatSync(path)
195-
const stat = vol.statSync(path)
191+
const lstat = vol.lstatSync(path, { bigint: true })
192+
const stat = vol.statSync(path, { bigint: true })
196193
return stat.isDirectory() || lstat.isDirectory()
197194
}
198195

@@ -212,7 +209,7 @@ export class VirtualApi implements FsApi {
212209
async stat(fullPath: string, transferId = -1): Promise<FileDescriptor> {
213210
try {
214211
const format = path.parse(fullPath)
215-
const stats = vol.lstatSync(fullPath)
212+
const stats = vol.lstatSync(fullPath, { bigint: true })
216213
const file: FileDescriptor = {
217214
dir: format.dir,
218215
fullname: format.base,
@@ -221,12 +218,13 @@ export class VirtualApi implements FsApi {
221218
cDate: stats.ctime,
222219
mDate: stats.mtime,
223220
bDate: stats.birthtime,
224-
length: stats.size,
225-
mode: stats.mode,
221+
length: Number(stats.size),
222+
mode: Number(stats.mode),
226223
isDir: stats.isDirectory(),
227224
readonly: false,
228225
type:
229-
(!stats.isDirectory() && filetype(stats.mode, stats.gid, stats.uid, format.ext.toLowerCase())) ||
226+
(!stats.isDirectory() &&
227+
filetype(Number(stats.mode), Number(stats.gid), Number(stats.uid), format.ext.toLowerCase())) ||
230228
'',
231229
isSym: stats.isSymbolicLink(),
232230
target: (stats.isSymbolicLink() && vol.readlinkSync(fullPath)) || null,
@@ -291,16 +289,16 @@ export class VirtualApi implements FsApi {
291289
static fileFromPath(fullPath: string): FileDescriptor {
292290
const format = path.parse(fullPath)
293291
let name = fullPath
294-
let stats: Partial<Stats> = null
292+
let stats: Partial<BigIntStats> = null
295293
let targetStats = null
296294

297295
try {
298296
// do not follow symlinks first
299-
stats = vol.lstatSync(fullPath)
297+
stats = vol.lstatSync(fullPath, { bigint: true })
300298
if (stats.isSymbolicLink()) {
301299
// get link target path first
302300
name = vol.readlinkSync(fullPath) as string
303-
targetStats = vol.statSync(fullPath)
301+
targetStats = vol.statSync(fullPath, { bigint: true })
304302
}
305303
} catch (err) {
306304
console.warn('error getting stats for', fullPath, err)
@@ -312,12 +310,12 @@ export class VirtualApi implements FsApi {
312310
ctime: new Date(),
313311
mtime: new Date(),
314312
birthtime: new Date(),
315-
size: stats ? stats.size : 0,
313+
size: stats ? stats.size : 0n,
316314
isDirectory: (): boolean => isDir,
317-
mode: -1,
315+
mode: -1n,
318316
isSymbolicLink: (): boolean => isSymLink,
319-
ino: 0,
320-
dev: 0,
317+
ino: 0n,
318+
dev: 0n,
321319
}
322320
}
323321

@@ -332,12 +330,13 @@ export class VirtualApi implements FsApi {
332330
cDate: stats.ctime,
333331
mDate: stats.mtime,
334332
bDate: stats.birthtime,
335-
length: stats.size,
336-
mode: mode,
333+
length: Number(stats.size),
334+
mode: Number(mode),
337335
isDir: targetStats ? targetStats.isDirectory() : stats.isDirectory(),
338336
readonly: false,
339337
type:
340-
(!(targetStats ? targetStats.isDirectory() : stats.isDirectory()) && filetype(mode, 0, 0, extension)) ||
338+
(!(targetStats ? targetStats.isDirectory() : stats.isDirectory()) &&
339+
filetype(Number(mode), 0, 0, extension)) ||
341340
'',
342341
isSym: stats.isSymbolicLink(),
343342
target: (stats.isSymbolicLink() && name) || null,
@@ -481,7 +480,7 @@ export class VirtualApi implements FsApi {
481480

482481
export function FolderExists(path: string): boolean {
483482
try {
484-
return vol.existsSync(path) && vol.lstatSync(path).isDirectory()
483+
return vol.existsSync(path) && vol.lstatSync(path, { bigint: true }).isDirectory()
485484
} catch (err) {
486485
return false
487486
}

0 commit comments

Comments
 (0)