@ethersphere/bee-js 12.1.0 → 12.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -15,10 +15,17 @@ class TarStream {
15
15
  });
16
16
  }
17
17
  beginFile(path, size) {
18
- if (path.length > 100) {
19
- throw new Error(`File name too long: ${path}`);
18
+ const { name, prefix, longLink } = splitPath(path);
19
+ if (longLink) {
20
+ const encoder = new TextEncoder();
21
+ const pathData = encoder.encode(path + '\0');
22
+ this.pieces.push(createLongLinkHeader(pathData.length));
23
+ this.pieces.push(pathData);
24
+ const padding = pathData.length % 512 === 0 ? 0 : 512 - (pathData.length % 512);
25
+ if (padding > 0)
26
+ this.pieces.push(new Uint8Array(padding));
20
27
  }
21
- const header = createHeader(path, size);
28
+ const header = createHeader(name, prefix, size);
22
29
  this.pieces.push(header);
23
30
  this.currentFileSize = 0;
24
31
  }
@@ -37,7 +44,46 @@ class TarStream {
37
44
  }
38
45
  }
39
46
  exports.TarStream = TarStream;
40
- function createHeader(path, size) {
47
+ function splitPath(path) {
48
+ if (path.length <= 100)
49
+ return { name: path, prefix: '', longLink: false };
50
+ for (let i = path.length - 1; i >= 0; i--) {
51
+ if (path[i] === '/') {
52
+ const name = path.substring(i + 1);
53
+ const prefix = path.substring(0, i);
54
+ if (name.length <= 100 && prefix.length <= 155)
55
+ return { name, prefix, longLink: false };
56
+ }
57
+ }
58
+ // Filename itself is > 100 chars or path > 255 chars — use GNU LongLink
59
+ const lastSlash = path.lastIndexOf('/');
60
+ const truncatedName = (lastSlash >= 0 ? path.substring(lastSlash + 1) : path).slice(0, 100);
61
+ return { name: truncatedName, prefix: '', longLink: true };
62
+ }
63
+ function createLongLinkHeader(size) {
64
+ const encoder = new TextEncoder();
65
+ function writeToBuffer(str, offset, length) {
66
+ const bytes = encoder.encode(str);
67
+ header.set(bytes.slice(0, length), offset);
68
+ }
69
+ const header = new Uint8Array(512);
70
+ header.fill(0);
71
+ writeToBuffer('././@LongLink', 0, 100);
72
+ writeToBuffer('0000644\0', 100, 8);
73
+ writeToBuffer('0000000\0', 108, 8);
74
+ writeToBuffer('0000000\0', 116, 8);
75
+ writeToBuffer(size.toString(8).padStart(11, '0') + '\0', 124, 12);
76
+ writeToBuffer('00000000000\0', 136, 12);
77
+ writeToBuffer(' ', 148, 8);
78
+ writeToBuffer('L', 156, 1);
79
+ writeToBuffer('ustar\0\0', 257, 8);
80
+ let checksum = 0;
81
+ for (let i = 0; i < 512; i++)
82
+ checksum += header[i];
83
+ writeToBuffer(checksum.toString(8).padStart(6, '0') + '\0 ', 148, 8);
84
+ return header;
85
+ }
86
+ function createHeader(name, prefix, size) {
41
87
  const encoder = new TextEncoder();
42
88
  function writeToBuffer(str, offset, length) {
43
89
  const bytes = encoder.encode(str);
@@ -47,7 +93,7 @@ function createHeader(path, size) {
47
93
  const header = new Uint8Array(512);
48
94
  header.fill(0, 0, 512);
49
95
  // File name, truncated to 100 characters if necessary
50
- writeToBuffer(path.slice(0, 100).padEnd(100, '\0'), 0, 100);
96
+ writeToBuffer(name.slice(0, 100).padEnd(100, '\0'), 0, 100);
51
97
  // File mode (octal) and null-terminated
52
98
  writeToBuffer('0000777\0', 100, 8);
53
99
  // UID and GID (octal) and null-terminated
@@ -64,11 +110,13 @@ function createHeader(path, size) {
64
110
  writeToBuffer('0', 156, 1);
65
111
  // USTAR magic and version
66
112
  writeToBuffer('ustar\0\0', 257, 8);
113
+ // UStar prefix field (offset 345, 155 bytes) — used when path > 100 but fits split
114
+ if (prefix)
115
+ writeToBuffer(prefix.slice(0, 155).padEnd(155, '\0'), 345, 155);
67
116
  // Calculate checksum
68
117
  let checksum = 0;
69
- for (let i = 0; i < 512; i++) {
118
+ for (let i = 0; i < 512; i++)
70
119
  checksum += header[i];
71
- }
72
120
  writeToBuffer(checksum.toString(8).padStart(6, '0') + '\0 ', 148, 8);
73
121
  return header;
74
122
  }
@@ -8,10 +8,16 @@ class TarStream {
8
8
  this.currentFileSize = 0;
9
9
  }
10
10
  beginFile(path, size) {
11
- if (path.length > 100) {
12
- throw new Error(`File name too long: ${path}`);
11
+ const { name, prefix, longLink } = splitPath(path);
12
+ if (longLink) {
13
+ const pathData = Buffer.from(path + '\0');
14
+ this.output.write(createLongLinkHeader(pathData.length));
15
+ this.output.write(pathData);
16
+ const padding = pathData.length % 512 === 0 ? 0 : 512 - (pathData.length % 512);
17
+ if (padding > 0)
18
+ this.output.write(Buffer.alloc(padding, 0));
13
19
  }
14
- const header = createHeader(path, size);
20
+ const header = createHeader(name, prefix, size);
15
21
  this.output.write(header);
16
22
  this.currentFileSize = 0;
17
23
  }
@@ -44,11 +50,44 @@ class TarStream {
44
50
  }
45
51
  }
46
52
  exports.TarStream = TarStream;
47
- function createHeader(path, size) {
53
+ function splitPath(path) {
54
+ if (path.length <= 100)
55
+ return { name: path, prefix: '', longLink: false };
56
+ for (let i = path.length - 1; i >= 0; i--) {
57
+ if (path[i] === '/') {
58
+ const name = path.substring(i + 1);
59
+ const prefix = path.substring(0, i);
60
+ if (name.length <= 100 && prefix.length <= 155)
61
+ return { name, prefix, longLink: false };
62
+ }
63
+ }
64
+ // Filename itself is > 100 chars or path > 255 chars — use GNU LongLink
65
+ const lastSlash = path.lastIndexOf('/');
66
+ const truncatedName = (lastSlash >= 0 ? path.substring(lastSlash + 1) : path).slice(0, 100);
67
+ return { name: truncatedName, prefix: '', longLink: true };
68
+ }
69
+ function createLongLinkHeader(size) {
70
+ const header = Buffer.alloc(512, 0);
71
+ header.write('././@LongLink', 0, 100);
72
+ header.write('0000644\0', 100, 8);
73
+ header.write('0000000\0', 108, 8);
74
+ header.write('0000000\0', 116, 8);
75
+ header.write(size.toString(8).padStart(11, '0') + '\0', 124, 12);
76
+ header.write('00000000000\0', 136, 12);
77
+ header.write(' ', 148, 8);
78
+ header.write('L', 156, 1);
79
+ header.write('ustar\0\0', 257, 8);
80
+ let checksum = 0;
81
+ for (let i = 0; i < 512; i++)
82
+ checksum += header[i];
83
+ header.write(checksum.toString(8).padStart(6, '0') + '\0 ', 148, 8);
84
+ return header;
85
+ }
86
+ function createHeader(name, prefix, size) {
48
87
  // Initialize header with zeros
49
88
  const header = Buffer.alloc(512, 0);
50
89
  // File name, truncated to 100 characters if necessary
51
- header.write(path.slice(0, 100).padEnd(100, '\0'), 0, 100);
90
+ header.write(name.slice(0, 100).padEnd(100, '\0'), 0, 100);
52
91
  // File mode (octal) and null-terminated
53
92
  header.write('0000777\0', 100, 8);
54
93
  // UID and GID (octal) and null-terminated
@@ -65,11 +104,13 @@ function createHeader(path, size) {
65
104
  header.write('0', 156, 1);
66
105
  // USTAR magic and version
67
106
  header.write('ustar\0\0', 257, 8);
107
+ // UStar prefix field (offset 345, 155 bytes) — used when path > 100 but fits split
108
+ if (prefix)
109
+ header.write(prefix.slice(0, 155).padEnd(155, '\0'), 345, 155);
68
110
  // Calculate checksum
69
111
  let checksum = 0;
70
- for (let i = 0; i < 512; i++) {
112
+ for (let i = 0; i < 512; i++)
71
113
  checksum += header[i];
72
- }
73
114
  header.write(checksum.toString(8).padStart(6, '0') + '\0 ', 148, 8);
74
115
  return header;
75
116
  }