async append(fn, opts) {
    if (typeof fn !== "string") {
      throw new Error("file name not specified");
    }
    let fileName = fn;
    // separate file name into two parts if needed
    let fileNamePrefix;
    if (fileName.length > 100) {
      let i = fileName.length;
      while (i >= 0) {
        i = fileName.lastIndexOf("/", i);
        if (i <= 155) {
          fileNamePrefix = fileName.substr(0, i);
          fileName = fileName.substr(i + 1);
          break;
        }
        i--;
      }
      const errMsg =
        "ustar format does not allow a long file name (length of [file name" +
        "prefix] + / + [file name] must be shorter than 256 bytes)";
      if (i < 0 || fileName.length > 100) {
        throw new Error(errMsg);
      } else {
        assert(fileNamePrefix != null);
        if (fileNamePrefix.length > 155) {
          throw new Error(errMsg);
        }
      }
    }
    opts = opts || {};
    // set meta data
    let info;
    if (opts.filePath) {
      info = await Deno.stat(opts.filePath);
      if (info.isDirectory) {
        info.size = 0;
        opts.reader = new Deno.Buffer();
      }
    }
    const mode = opts.fileMode || info && info.mode ||
        parseInt("777", 8) & 4095,
      mtime = Math.floor(
        opts.mtime ?? (info?.mtime ?? new Date()).valueOf() / 1000,
      ),
      uid = opts.uid || 0,
      gid = opts.gid || 0;
    if (typeof opts.owner === "string" && opts.owner.length >= 32) {
      throw new Error(
        "ustar format does not allow owner name length >= 32 bytes",
      );
    }
    if (typeof opts.group === "string" && opts.group.length >= 32) {
      throw new Error(
        "ustar format does not allow group name length >= 32 bytes",
      );
    }
    const fileSize = info?.size ?? opts.contentSize;
    assert(fileSize != null, "fileSize must be set");
    const type = opts.type
      ? FileTypes[opts.type]
      : info?.isDirectory
      ? FileTypes.directory
      : FileTypes.file;
    const tarData = {
      fileName,
      fileNamePrefix,
      fileMode: pad(mode, 7),
      uid: pad(uid, 7),
      gid: pad(gid, 7),
      fileSize: pad(fileSize, 11),
      mtime: pad(mtime, 11),
      checksum: "        ",
      type: type.toString(),
      ustar,
      owner: opts.owner || "",
      group: opts.group || "",
      filePath: opts.filePath,
      reader: opts.reader,
    };
    // calculate the checksum
    let checksum = 0;
    const encoder = new TextEncoder();
    Object.keys(tarData).filter((key) =>
      [
        "filePath",
        "reader",
      ].indexOf(key) < 0
    ).forEach(function (key) {
      checksum += encoder.encode(tarData[key]).reduce((p, c) => p + c, 0);
    });
    tarData.checksum = pad(checksum, 6) + "\u0000 ";
    this.data.push(tarData);
  }
/**
   * Append a file to this tar archive
   * @param fn file name
   *                 e.g., test.txt; use slash for directory separators
   * @param opts options
   */
Append a file to this tar archive
@param fn file name
e.g., test.txt; use slash for directory separators
@param opts options
Append a file to this tar archive @param fn file name e . g . test . txt ; use slash for directory separators @param opts options
async append(fn, opts) {
    if (typeof fn !== "string") {
      throw new Error("file name not specified");
    }
    let fileName = fn;
    let fileNamePrefix;
    if (fileName.length > 100) {
      let i = fileName.length;
      while (i >= 0) {
        i = fileName.lastIndexOf("/", i);
        if (i <= 155) {
          fileNamePrefix = fileName.substr(0, i);
          fileName = fileName.substr(i + 1);
          break;
        }
        i--;
      }
      const errMsg =
        "ustar format does not allow a long file name (length of [file name" +
        "prefix] + / + [file name] must be shorter than 256 bytes)";
      if (i < 0 || fileName.length > 100) {
        throw new Error(errMsg);
      } else {
        assert(fileNamePrefix != null);
        if (fileNamePrefix.length > 155) {
          throw new Error(errMsg);
        }
      }
    }
    opts = opts || {};
    let info;
    if (opts.filePath) {
      info = await Deno.stat(opts.filePath);
      if (info.isDirectory) {
        info.size = 0;
        opts.reader = new Deno.Buffer();
      }
    }
    const mode = opts.fileMode || info && info.mode ||
        parseInt("777", 8) & 4095,
      mtime = Math.floor(
        opts.mtime ?? (info?.mtime ?? new Date()).valueOf() / 1000,
      ),
      uid = opts.uid || 0,
      gid = opts.gid || 0;
    if (typeof opts.owner === "string" && opts.owner.length >= 32) {
      throw new Error(
        "ustar format does not allow owner name length >= 32 bytes",
      );
    }
    if (typeof opts.group === "string" && opts.group.length >= 32) {
      throw new Error(
        "ustar format does not allow group name length >= 32 bytes",
      );
    }
    const fileSize = info?.size ?? opts.contentSize;
    assert(fileSize != null, "fileSize must be set");
    const type = opts.type
      ? FileTypes[opts.type]
      : info?.isDirectory
      ? FileTypes.directory
      : FileTypes.file;
    const tarData = {
      fileName,
      fileNamePrefix,
      fileMode: pad(mode, 7),
      uid: pad(uid, 7),
      gid: pad(gid, 7),
      fileSize: pad(fileSize, 11),
      mtime: pad(mtime, 11),
      checksum: "        ",
      type: type.toString(),
      ustar,
      owner: opts.owner || "",
      group: opts.group || "",
      filePath: opts.filePath,
      reader: opts.reader,
    };
    let checksum = 0;
    const encoder = new TextEncoder();
    Object.keys(tarData).filter((key) =>
      [
        "filePath",
        "reader",
      ].indexOf(key) < 0
    ).forEach(function (key) {
      checksum += encoder.encode(tarData[key]).reduce((p, c) => p + c, 0);
    });
    tarData.checksum = pad(checksum, 6) + "\u0000 ";
    this.data.push(tarData);
  }
async append ( fn , opts ) { if ( typeof fn !== "string" ) { throw new Error ( "file name not specified" ) ; } let fileName = fn ; let fileNamePrefix ; if ( fileName . length > 100 ) { let i = fileName . length ; while ( i >= 0 ) { i = fileName . lastIndexOf ( "/" , i ) ; if ( i <= 155 ) { fileNamePrefix = fileName . substr ( 0 , i ) ; fileName = fileName . substr ( i + 1 ) ; break ; } i -- ; } const errMsg = "ustar format does not allow a long file name (length of [file name" + "prefix] + / + [file name] must be shorter than 256 bytes)" ; if ( i < 0 || fileName . length > 100 ) { throw new Error ( errMsg ) ; } else { assert ( fileNamePrefix != null ) ; if ( fileNamePrefix . length > 155 ) { throw new Error ( errMsg ) ; } } } opts = opts || { } ; let info ; if ( opts . filePath ) { info = await Deno . stat ( opts . filePath ) ; if ( info . isDirectory ) { info . size = 0 ; opts . reader = new Deno . Buffer ( ) ; } } const mode = opts . fileMode || info && info . mode || parseInt ( "777" , 8 ) & 4095 , mtime = Math . floor ( opts . mtime ?? ( info ?. mtime ?? new Date ( ) ) . valueOf ( ) / 1000 , ) , uid = opts . uid || 0 , gid = opts . gid || 0 ; if ( typeof opts . owner === "string" && opts . owner . length >= 32 ) { throw new Error ( "ustar format does not allow owner name length >= 32 bytes" , ) ; } if ( typeof opts . group === "string" && opts . group . length >= 32 ) { throw new Error ( "ustar format does not allow group name length >= 32 bytes" , ) ; } const fileSize = info ?. size ?? opts . contentSize ; assert ( fileSize != null , "fileSize must be set" ) ; const type = opts . type ? FileTypes [ opts . type ] : info ?. isDirectory ? FileTypes . directory : FileTypes . file ; const tarData = { fileName , fileNamePrefix , fileMode : pad ( mode , 7 ) , uid : pad ( uid , 7 ) , gid : pad ( gid , 7 ) , fileSize : pad ( fileSize , 11 ) , mtime : pad ( mtime , 11 ) , checksum : "        " , type : type . toString ( ) , ustar , owner : opts . owner || "" , group : opts . group || "" , filePath : opts . filePath , reader : opts . reader , } ; let checksum = 0 ; const encoder = new TextEncoder ( ) ; Object . keys ( tarData ) . filter ( ( key ) => [ "filePath" , "reader" , ] . indexOf ( key ) < 0 ) . forEach ( function ( key ) { checksum += encoder . encode ( tarData [ key ] ) . reduce ( ( p , c ) => p + c , 0 ) ; } ) ; tarData . checksum = pad ( checksum , 6 ) + "\u0000 " ; this . data . push ( tarData ) ; }
Append a file to this tar archive
 @param fn file name
                 e.g., test.txt; use slash for directory separators
 @param opts options
Append a file to this tar archive @param fn file name e . g . test . txt ; use slash for directory separators @param opts options
// separate file name into two parts if needed // set meta data // calculate the checksum