// field paths that every tar file must have. // header is padded to 512 bytes. var f = 0 , fields = {} , path = fields.path = f++ , mode = fields.mode = f++ , uid = fields.uid = f++ , gid = fields.gid = f++ , size = fields.size = f++ , mtime = fields.mtime = f++ , cksum = fields.cksum = f++ , type = fields.type = f++ , linkpath = fields.linkpath = f++ , headerSize = 512 , blockSize = 512 , fieldSize = [] fieldSize[path] = 100 fieldSize[mode] = 8 fieldSize[uid] = 8 fieldSize[gid] = 8 fieldSize[size] = 12 fieldSize[mtime] = 12 fieldSize[cksum] = 8 fieldSize[type] = 1 fieldSize[linkpath] = 100 // "ustar\0" may introduce another bunch of headers. // these are optional, and will be nulled out if not present. var ustar = fields.ustar = f++ , ustarver = fields.ustarver = f++ , uname = fields.uname = f++ , gname = fields.gname = f++ , devmaj = fields.devmaj = f++ , devmin = fields.devmin = f++ , prefix = fields.prefix = f++ , fill = fields.fill = f++ // terminate fields. fields[f] = null fieldSize[ustar] = 6 fieldSize[ustarver] = 2 fieldSize[uname] = 32 fieldSize[gname] = 32 fieldSize[devmaj] = 8 fieldSize[devmin] = 8 fieldSize[prefix] = 155 fieldSize[fill] = 12 // nb: prefix field may in fact be 130 bytes of prefix, // a null char, 12 bytes for atime, 12 bytes for ctime. // // To recognize this format: // 1. prefix[130] === ' ' or '\0' // 2. atime and ctime are octal numeric values // 3. atime and ctime have ' ' in their last byte var fieldEnds = {} , fieldOffs = {} , fe = 0 for (var i = 0; i < f; i ++) { fieldOffs[i] = fe fieldEnds[i] = (fe += fieldSize[i]) } // build a translation table of field paths. Object.keys(fields).forEach(function (f) { if (fields[f] !== null) fields[fields[f]] = f }) // different values of the 'type' field // paths match the values of Stats.isX() functions, where appropriate var types = { 0: "File" , "\0": "OldFile" // like 0 , "": "OldFile" , 1: "Link" , 2: "SymbolicLink" , 3: "CharacterDevice" , 4: "BlockDevice" , 5: "Directory" , 6: "FIFO" , 7: "ContiguousFile" // like 0 // posix headers , g: "GlobalExtendedHeader" // k=v for the rest of the archive , x: "ExtendedHeader" // k=v for the next file // vendor-specific stuff , A: "SolarisACL" // skip , D: "GNUDumpDir" // like 5, but with data, which should be skipped , I: "Inode" // metadata only, skip , K: "NextFileHasLongLinkpath" // data = link path of next file , L: "NextFileHasLongPath" // data = path of next file , M: "ContinuationFile" // skip , N: "OldGnuLongPath" // like L , S: "SparseFile" // skip , V: "TapeVolumeHeader" // skip , X: "OldExtendedHeader" // like x } Object.keys(types).forEach(function (t) { types[types[t]] = types[types[t]] || t }) // values for the mode field var modes = { suid: 04000 // set uid on extraction , sgid: 02000 // set gid on extraction , svtx: 01000 // set restricted deletion flag on dirs on extraction , uread: 0400 , uwrite: 0200 , uexec: 0100 , gread: 040 , gwrite: 020 , gexec: 010 , oread: 4 , owrite: 2 , oexec: 1 , all: 07777 } var numeric = { mode: true , uid: true , gid: true , size: true , mtime: true , devmaj: true , devmin: true , cksum: true , atime: true , ctime: true , dev: true , ino: true , nlink: true } Object.keys(modes).forEach(function (t) { modes[modes[t]] = modes[modes[t]] || t }) var knownExtended = { atime: true , charset: true , comment: true , ctime: true , gid: true , gname: true , linkpath: true , mtime: true , path: true , realtime: true , security: true , size: true , uid: true , uname: true } exports.fields = fields exports.fieldSize = fieldSize exports.fieldOffs = fieldOffs exports.fieldEnds = fieldEnds exports.types = types exports.modes = modes exports.numeric = numeric exports.headerSize = headerSize exports.blockSize = blockSize exports.knownExtended = knownExtended exports.Pack = require("./lib/pack.js") exports.Parse = require("./lib/parse.js") exports.Extract = require("./lib/extract.js")