Skip to content

Commit f16adb3

Browse files
committed
chore: cleaned up code
1 parent fae11aa commit f16adb3

File tree

12 files changed

+453
-487
lines changed

12 files changed

+453
-487
lines changed

src/Generator.ts

Lines changed: 52 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { FileType, FileStat } from './types';
2-
import { GeneratorState, EntryType } from './types';
2+
import { GeneratorState, EntryType, HeaderSize } from './types';
33
import * as errors from './errors';
44
import * as utils from './utils';
55
import * as constants from './constants';
@@ -27,14 +27,14 @@ import * as constants from './constants';
2727
* 500 12 '\0' (unused)
2828
*
2929
* Note that all numbers are in stringified octal format.
30-
*
30+
*
3131
* The following data will be left blank (null):
3232
* - Link name
3333
* - Owner user name
3434
* - Owner group name
3535
* - Device major
3636
* - Device minor
37-
*
37+
*
3838
* This is because this implementation does not interact with linked files.
3939
* Owner user name and group name cannot be extracted via regular stat-ing,
4040
* so it is left blank. In virtual situations, this field won't be useful
@@ -43,16 +43,40 @@ import * as constants from './constants';
4343
* these fields have been left blank.
4444
*/
4545
class Generator {
46-
protected state: GeneratorState = GeneratorState.READY;
46+
protected state: GeneratorState = GeneratorState.HEADER;
4747
protected remainingBytes = 0;
4848

49-
protected generateHeader(filePath: string, type: FileType, stat: FileStat) {
49+
protected generateHeader(filePath: string, type: FileType, stat: FileStat): Uint8Array {
5050
if (filePath.length > 255) {
5151
throw new errors.ErrorVirtualTarGeneratorInvalidFileName(
5252
'The file name must shorter than 255 characters',
5353
);
5454
}
5555

56+
if (stat?.size != null && stat?.size > 0o7777777) {
57+
throw new errors.ErrorVirtualTarGeneratorInvalidStat(
58+
'The file size must be smaller than 7.99 GiB (8,589,934,591 bytes)',
59+
);
60+
}
61+
62+
if (
63+
stat?.username != null &&
64+
stat?.username.length > HeaderSize.OWNER_USERNAME
65+
) {
66+
throw new errors.ErrorVirtualTarGeneratorInvalidStat(
67+
`The username must not exceed ${HeaderSize.OWNER_USERNAME} bytes`,
68+
);
69+
}
70+
71+
if (
72+
stat?.groupname != null &&
73+
stat?.groupname.length > HeaderSize.OWNER_GROUPNAME
74+
) {
75+
throw new errors.ErrorVirtualTarGeneratorInvalidStat(
76+
`The groupname must not exceed ${HeaderSize.OWNER_GROUPNAME} bytes`,
77+
);
78+
}
79+
5680
const header = new Uint8Array(constants.BLOCK_SIZE);
5781

5882
// Every directory in tar must have a trailing slash
@@ -66,6 +90,8 @@ class Generator {
6690
utils.writeFileMode(header, stat.mode);
6791
utils.writeOwnerUid(header, stat.uid);
6892
utils.writeOwnerGid(header, stat.gid);
93+
utils.writeOwnerUserName(header, stat.username);
94+
utils.writeOwnerGroupName(header, stat.groupname);
6995
utils.writeFileSize(header, stat.size);
7096
utils.writeFileMtime(header, stat.mtime);
7197

@@ -77,11 +103,11 @@ class Generator {
77103
}
78104

79105
generateFile(filePath: string, stat: FileStat): Uint8Array {
80-
if (this.state === GeneratorState.READY) {
106+
if (this.state === GeneratorState.HEADER) {
81107
// Make sure the size is valid
82108
if (stat.size == null) {
83109
throw new errors.ErrorVirtualTarGeneratorInvalidStat(
84-
'Files should have valid file sizes',
110+
'Files must have valid file sizes',
85111
);
86112
}
87113

@@ -97,59 +123,58 @@ class Generator {
97123
return generatedBlock;
98124
}
99125
throw new errors.ErrorVirtualTarGeneratorInvalidState(
100-
`Expected state ${GeneratorState[GeneratorState.READY]} but got ${
126+
`Expected state ${GeneratorState[GeneratorState.HEADER]} but got ${
101127
GeneratorState[this.state]
102128
}`,
103129
);
104130
}
105131

106-
generateDirectory(filePath: string, stat: FileStat): Uint8Array {
107-
if (this.state === GeneratorState.READY) {
132+
generateDirectory(filePath: string, stat?: FileStat): Uint8Array {
133+
if (this.state === GeneratorState.HEADER) {
134+
// The size is zero for directories. Override this value in the stat if
135+
// set.
108136
const directoryStat: FileStat = {
137+
...stat,
109138
size: 0,
110-
mode: stat.mode,
111-
mtime: stat.mtime,
112-
uid: stat.uid,
113-
gid: stat.gid,
114139
};
115140
return this.generateHeader(filePath, 'directory', directoryStat);
116141
}
117142
throw new errors.ErrorVirtualTarGeneratorInvalidState(
118-
`Expected state ${GeneratorState[GeneratorState.READY]} but got ${
143+
`Expected state ${GeneratorState[GeneratorState.HEADER]} but got ${
119144
GeneratorState[this.state]
120145
}`,
121146
);
122147
}
123148

124149
generateExtended(size: number): Uint8Array {
125-
if (this.state === GeneratorState.READY) {
150+
if (this.state === GeneratorState.HEADER) {
126151
this.state = GeneratorState.DATA;
127152
this.remainingBytes = size;
128153
return this.generateHeader('./PaxHeader', 'extended', { size });
129154
}
130155
throw new errors.ErrorVirtualTarGeneratorInvalidState(
131-
`Expected state ${GeneratorState[GeneratorState.READY]} but got ${
156+
`Expected state ${GeneratorState[GeneratorState.HEADER]} but got ${
132157
GeneratorState[this.state]
133158
}`,
134159
);
135160
}
136161

137162
generateData(data: Uint8Array): Uint8Array {
138-
if (data.byteLength > constants.BLOCK_SIZE) {
139-
throw new errors.ErrorVirtualTarGeneratorBlockSize(
140-
`Expected data to be ${constants.BLOCK_SIZE} bytes but received ${data.byteLength} bytes`,
141-
);
142-
}
143-
144163
if (this.state === GeneratorState.DATA) {
164+
if (data.byteLength > constants.BLOCK_SIZE) {
165+
throw new errors.ErrorVirtualTarGeneratorBlockSize(
166+
`Expected data to be ${constants.BLOCK_SIZE} bytes but received ${data.byteLength} bytes`,
167+
);
168+
}
169+
145170
if (this.remainingBytes >= constants.BLOCK_SIZE) {
146171
this.remainingBytes -= constants.BLOCK_SIZE;
147-
if (this.remainingBytes === 0) this.state = GeneratorState.READY;
172+
if (this.remainingBytes === 0) this.state = GeneratorState.HEADER;
148173
return data;
149174
} else {
150175
// Update state
151176
this.remainingBytes = 0;
152-
this.state = GeneratorState.READY;
177+
this.state = GeneratorState.HEADER;
153178

154179
// Pad the remaining data with nulls
155180
const paddedData = new Uint8Array(constants.BLOCK_SIZE);
@@ -168,9 +193,9 @@ class Generator {
168193
// Creates a single null block. A null block is a block filled with all zeros.
169194
// This is needed to end the archive, as two of these blocks mark the end of
170195
// archive.
171-
generateEnd() {
196+
generateEnd(): Uint8Array {
172197
switch (this.state) {
173-
case GeneratorState.READY:
198+
case GeneratorState.HEADER:
174199
this.state = GeneratorState.NULL;
175200
break;
176201
case GeneratorState.NULL:

0 commit comments

Comments
 (0)