include file's mode in zip

Massimo Melina committed Apr 20, 2022 at 22:54 UTC f21854d5f62732d79a92132da9195e5e516837d0
2 files changed +8 -5
server/src/QuickZipStream.ts
+7 -5
@@ -16,12 +16,13 @@ interface ZipSource {
16 getData: () => Readable // deferred stream, so that we don't keep many open files because of calculateSize()
17 size: number
18 ts: Date
19 + mode?: number
20 }
21 export class QuickZipStream extends Readable {
22 private workingFile = false
23 private numberOfFiles: number = 0
24 private finished = false
24 - private readonly centralDir: ({ size:number, crc:number, ts:Date, pathAsBuffer:Buffer, offset:number, version:number })[] = []
25 + private readonly centralDir: ({ size:number, crc:number, ts:Date, pathAsBuffer:Buffer, offset:number, version:number, extAttr: number })[] = []
26 private dataWritten = 0
27 private prewalk?: ZipSource[]
28
@@ -69,7 +70,7 @@ export class QuickZipStream extends Readable {
70 if (!file)
71 return this.closeArchive()
72 ++this.numberOfFiles
72 - let { path, getData, size, ts } = file
73 + let { path, getData, size, ts, mode } = file
74 const data = getData()
75 const pathAsBuffer = Buffer.from(path, 'utf8')
76 const crc32 = await crc32provider
@@ -102,7 +103,8 @@ export class QuickZipStream extends Readable {
103 this.workingFile = true
104 data.on('end', ()=>{
105 this.workingFile = false
105 - this.centralDir.push({ size, crc:crc!, pathAsBuffer, ts, offset, version })
106 + const extAttr = !mode ? 0 : (mode | 0x8000) * 0x10000 // it's like <<16 but doesn't overflow so easily
107 + this.centralDir.push({ size, crc:crc!, pathAsBuffer, ts, offset, version, extAttr })
108 const sizeSize = size > ZIP64_LIMIT ? 8 : 4
109 this._push([
110 4, 0x08074b50,
@@ -116,7 +118,7 @@ export class QuickZipStream extends Readable {
118 closeArchive() {
119 this.finished = true
120 let centralOffset = this.dataWritten
119 - for (let { size, ts, crc, offset, pathAsBuffer, version } of this.centralDir) {
121 + for (let { size, ts, crc, offset, pathAsBuffer, version, extAttr } of this.centralDir) {
122 const extra = []
123 if (size > ZIP64_LIMIT) {
124 extra.push(size, size)
@@ -145,7 +147,7 @@ export class QuickZipStream extends Readable {
147 2, 0, //comment length
148 2, 0, // disk
149 2, 0, // attr
148 - 4, 0, // ext.attr
150 + 4, extAttr,
151 4, offset,
152 ])
153 this._push(pathAsBuffer)
server/src/zip.ts
+1
@@ -41,6 +41,7 @@ export async function zipStreamFromFolder(node: VfsNode, ctx: Koa.Context) {
41 path: name,
42 size: st.size,
43 ts: st.mtime || st.ctime,
44 + mode: st.mode,
45 getData: () => createReadStream(source)
46 }
47 }