title: Golang tarring directory
body: <p>I am having trouble figuring out how to write a directory into tarball's headerinfo. For example, I have this directory structure:</p>
  
  <pre><code>test [dir]
  -- test1.txt
      -- subDirA [sub dir]
           -- test2.txt
  </code></pre>
  
  <p>If I tar up test using my Go tar executable, it will untar and have the original structure. If I do a tar -tvf on the tarball, the listing will be:</p>
  
  <pre><code>test/test1.txt 
  test/subDirA/test2.txt
  </code></pre>
  
  <p>However if I manually do a tar -cvf of test and then do a tar -tvf, the listing will be:</p>
  
  <pre><code>test/
  test/test1.txt
  test/subDirA/
  test/subDirA/test2.txt
  </code></pre>
  
  <p>This is what I want my Go tarring program to do as well. In my Go program, I tried to add a new method <code>writeDirToTar</code> to deal with adding directories into the tarWriter. I call either writeFileToTar or writeDirToTar from a fileWalk function. I am getting a "test/subDirA is a directory" error when I call <code>io.Copy(tarWriter, file)</code> in <code>writeDirToTar</code>, which kind of makes sense. Is there a workaround for this?</p>
  
  <pre><code>func writeToTar(fileDir string,
          sourceBase string,
          tarWriter *tar.Writer,
          f os.FileInfo) error {
  
          file, err := os.Open(fileDir)
          if err != nil {
                  log.Print("error opening file")
                  return err
          }
          defer file.Close()
  
          // relative paths are used to preserve the directory paths in each file path
          relativePath, err := filepath.Rel(sourceBase, fileDir)
  
          tarheader := new(tar.Header)
          tarheader.Name = relativePath
          tarheader.Size = f.Size()
          tarheader.Mode = int64(f.Mode())
          tarheader.ModTime = f.ModTime()
  
          err = tarWriter.WriteHeader(tarheader)
          if err != nil {
                  log.Print("error writing tarHeader")
                  return err
          }
          _, err = io.Copy(tarWriter, file)
          if err != nil {
                  log.Print("error writing to tarWriter")
                  return err
          }
          return nil
  }
  
  func writeDirToTar(fileDir string,
          sourceBase string,
          tarWriter *tar.Writer,
          f os.FileInfo) error {
  
          file, err := os.Open(fileDir)
          if err != nil {
                  log.Print("error opening file")
                  return err
          }
          defer file.Close()
  
          // relative paths are used to preserve the directory paths in each file path
          relativePath, err := filepath.Rel(sourceBase, fileDir)
  
          if tarHeader, err := tar.FileInfoHeader(f, relativePath); err != nil {
                  log.Print("error writing tarHeader")
                  return err
          }
  
          tarHeader.Name = relativePath
          tarheader.Mode = int64(f.Mode())
          tarheader.ModTime = f.ModTime()
  
          _, err = io.Copy(tarWriter, file)
          if err != nil {
                  log.Print("error writing to tarWriter")
                  return err
          }
          return nil
  
  }
  </code></pre>