forked from jvilk/BrowserFS
-
Notifications
You must be signed in to change notification settings - Fork 0
/
node_fs_stats.ts
208 lines (187 loc) · 5.39 KB
/
node_fs_stats.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
import * as fs from 'fs';
/**
* Indicates the type of the given file. Applied to 'mode'.
*/
export enum FileType {
FILE = 0x8000,
DIRECTORY = 0x4000,
SYMLINK = 0xA000
}
/**
* Emulation of Node's `fs.Stats` object.
*
* Attribute descriptions are from `man 2 stat'
* @see http://nodejs.org/api/fs.html#fs_class_fs_stats
* @see http://man7.org/linux/man-pages/man2/stat.2.html
*/
export default class Stats implements fs.Stats {
public static fromBuffer(buffer: Buffer): Stats {
const size = buffer.readUInt32LE(0),
mode = buffer.readUInt32LE(4),
atime = buffer.readDoubleLE(8),
mtime = buffer.readDoubleLE(16),
ctime = buffer.readDoubleLE(24);
return new Stats(mode & 0xF000, size, mode & 0xFFF, atime, mtime, ctime);
}
/**
* Clones the stats object.
*/
public static clone(s: Stats): Stats {
return new Stats(s.mode & 0xF000, s.size, s.mode & 0xFFF, s.atimeMs, s.mtimeMs, s.ctimeMs, s.birthtimeMs);
}
public blocks: number;
public mode: number;
/**
* UNSUPPORTED ATTRIBUTES
* I assume no one is going to need these details, although we could fake
* appropriate values if need be.
*/
// ID of device containing file
public dev: number = 0;
// inode number
public ino: number = 0;
// device ID (if special file)
public rdev: number = 0;
// number of hard links
public nlink: number = 1;
// blocksize for file system I/O
public blksize: number = 4096;
// @todo Maybe support these? atm, it's a one-user filesystem.
// user ID of owner
public uid: number = 0;
// group ID of owner
public gid: number = 0;
// XXX: Some file systems stash data on stats objects.
public fileData: Buffer | null = null;
public atimeMs: number;
public mtimeMs: number;
public ctimeMs: number;
public birthtimeMs: number;
public size: number;
public get atime(): Date {
return new Date(this.atimeMs);
}
public get mtime(): Date {
return new Date(this.mtimeMs);
}
public get ctime(): Date {
return new Date(this.ctimeMs);
}
public get birthtime(): Date {
return new Date(this.birthtimeMs);
}
/**
* Provides information about a particular entry in the file system.
* @param itemType Type of the item (FILE, DIRECTORY, SYMLINK, or SOCKET)
* @param size Size of the item in bytes. For directories/symlinks,
* this is normally the size of the struct that represents the item.
* @param mode Unix-style file mode (e.g. 0o644)
* @param atimeMs time of last access, in milliseconds since epoch
* @param mtimeMs time of last modification, in milliseconds since epoch
* @param ctimeMs time of last time file status was changed, in milliseconds since epoch
* @param birthtimeMs time of file creation, in milliseconds since epoch
*/
constructor(
itemType: FileType,
size: number,
mode?: number,
atimeMs?: number,
mtimeMs?: number,
ctimeMs?: number,
birthtimeMs?: number) {
this.size = size;
let currentTime = 0;
if (typeof(atimeMs) !== 'number') {
currentTime = Date.now();
atimeMs = currentTime;
}
if (typeof(mtimeMs) !== 'number') {
if (!currentTime) {
currentTime = Date.now();
}
mtimeMs = currentTime;
}
if (typeof(ctimeMs) !== 'number') {
if (!currentTime) {
currentTime = Date.now();
}
ctimeMs = currentTime;
}
if (typeof(birthtimeMs) !== 'number') {
if (!currentTime) {
currentTime = Date.now();
}
birthtimeMs = currentTime;
}
this.atimeMs = atimeMs;
this.ctimeMs = ctimeMs;
this.mtimeMs = mtimeMs;
this.birthtimeMs = birthtimeMs;
if (!mode) {
switch (itemType) {
case FileType.FILE:
this.mode = 0x1a4;
break;
case FileType.DIRECTORY:
default:
this.mode = 0x1ff;
}
} else {
this.mode = mode;
}
// number of 512B blocks allocated
this.blocks = Math.ceil(size / 512);
// Check if mode also includes top-most bits, which indicate the file's
// type.
if (this.mode < 0x1000) {
this.mode |= itemType;
}
}
public toBuffer(): Buffer {
const buffer = Buffer.alloc(32);
buffer.writeUInt32LE(this.size, 0);
buffer.writeUInt32LE(this.mode, 4);
buffer.writeDoubleLE(this.atime.getTime(), 8);
buffer.writeDoubleLE(this.mtime.getTime(), 16);
buffer.writeDoubleLE(this.ctime.getTime(), 24);
return buffer;
}
/**
* @return [Boolean] True if this item is a file.
*/
public isFile(): boolean {
return (this.mode & 0xF000) === FileType.FILE;
}
/**
* @return [Boolean] True if this item is a directory.
*/
public isDirectory(): boolean {
return (this.mode & 0xF000) === FileType.DIRECTORY;
}
/**
* @return [Boolean] True if this item is a symbolic link (only valid through lstat)
*/
public isSymbolicLink(): boolean {
return (this.mode & 0xF000) === FileType.SYMLINK;
}
/**
* Change the mode of the file. We use this helper function to prevent messing
* up the type of the file, which is encoded in mode.
*/
public chmod(mode: number): void {
this.mode = (this.mode & 0xF000) | mode;
}
// We don't support the following types of files.
public isSocket(): boolean {
return false;
}
public isBlockDevice(): boolean {
return false;
}
public isCharacterDevice(): boolean {
return false;
}
public isFIFO(): boolean {
return false;
}
}