Unzipping from a shared smb folder golang - go

I'm using the code below to iterate through a folder (unzipping .zip files locally, performing actions on them etc).
func extractZipWithPassword(localPath string, pathToServer string) {
filepath.Walk(localPath, func(path string, info os.FileInfo, err error) error {
extension := filepath.Ext(path)
fileName := filepath.Base(path)
if extension == ".zip" {
zip_password := "password"
outDirZIP := filepath.Dir(path) + "/" + strings.TrimSuffix(fileName, extension)
os.Mkdir(outDirZIP, 0777)
commandString := fmt.Sprintf(`unzip -P %s %s -d %s`, zip_password, path, outDirZIP)
commandSlice := strings.Fields(commandString)
fmt.Println(commandString)
c := exec.Command(commandSlice[0], commandSlice[1:]...)
c.Run()
zipCount++
iterateThroughPE(outDirZIP)
parsePKCS7(outDirZIP)
splitter(start_string, end_string, outDirZIP)
return nil
} else {
fmt.Println("")
return nil
}
})
}
However now I need to extract archives from an SMB folder that requires login+password combination to access.
I tried using this lib github.com/hirochachacha/go-smb2 to access the shared folder, but to no success.
Is there a way to straight up unzip .zip files to a local folder of my choice with Go?
If there's not, what are my options?
UPDATE
Got the share mounted with go-smb2, not sure how to proceed next.
func listShares(path string) {
conn, err := net.Dial("tcp", "ip:port")
if err != nil {
panic(err)
}
defer conn.Close()
d := &smb2.Dialer{
Initiator: &smb2.NTLMInitiator{
User: "user",
Password: "pw",
},
}
s, err := d.Dial(conn)
if err != nil {
panic(err)
}
defer s.Logoff()
names, err := s.ListSharenames()
if err != nil {
panic(err)
}
for _, name := range names {
fmt.Println(name)
}
fs, err := s.Mount("sharename")
if err != nil {
panic(err)
}
defer fs.Umount()
}

Related

Refactor function that reading files from folders tree

I have the following structure of my project like that:
main.go
/data
/1
1.json
/2
2.json
/3
3.json
And I have the following function that works well
const (
data = "./data"
)
type Hello struct {
S string `json:"hello"`
}
func myFunc() {
folders, err := os.ReadDir(data)
if err != nil {
log.Fatalf("read dir: %s", err)
}
for _, folder := range folders {
path := filepath.Join(data, folder.Name())
files, err := os.ReadDir(path)
if err != nil {
log.Fatalf("read dir: %s", err)
}
for _, file := range files {
pathToFile := filepath.Join(path, file.Name())
b, err := os.ReadFile(pathToFile)
if err != nil {
log.Println(err)
}
h := Hello{}
err = json.Unmarshal(b, &h)
if err != nil {
log.Printf("unmarshall erro: %w\n", err)
}
fmt.Println(h)
}
}
}
I should refactor my data tree and divide data folder into two additional folders. So my structure should be like this:
main.go
/data
/dog
/1
1.json
/2
2.json
/cat
/3
3.json
So I need to fix my function according to this structure of the files.
I don't want to hardcode and make the solution with additional for loop. But I think it is not good solution.
func myfunc() {
subFolders, err := os.ReadDir(data)
if err != nil {
log.Fatalf("read dir: %s", err)
}
for _, subFolder := range subFolders {
pathToSubFolder := filepath.Join(data, subFolder.Name())
folders, err := os.ReadDir(pathToSubFolder)
if err != nil {
log.Fatalf("read dir1: %s", err)
}
for _, folder := range folders {
path := filepath.Join(pathToSubFolder, folder.Name())
files, err := os.ReadDir(path)
if err != nil {
log.Fatalf("read dir2: %s", err)
}
for _, file := range files {
pathToFile := filepath.Join(path, file.Name())
b, err := os.ReadFile(pathToFile)
if err != nil {
log.Println(err)
}
h := Hello{}
err = json.Unmarshal(b, &h)
if err != nil {
log.Printf("unmarshall erro: %w\n", err)
}
fmt.Println(h)
}
}
}
}
This soultion works but can anyone suggest another solution that could be better?
Thanks in advance

Got error SSH_FX_FAILURE when download file from sftp

I use sftp library to download file from sftp to local drive. I use copy function to copy content from remote to local, but I got error SSH_FX_FAILURE when downloading many files. I dont know what mean this error. My go service deployed in kubernetes
for _, file := range remoteFiles {
if file.IsDir() {
continue
}
remoteFilePath := path.Join("/download", file.Name())
remoteFile, err := ftp.Conn.Open(remoteFilePath)
if err != nil {
continue
}
localFilePath := path.Join(/"local/downloaded", file.Name())
localFile, err := os.Create(localFilePath)
if err != nil {
remoteFile.Close()
continue
}
_, err = io.Copy(localFile, remoteFile)
if err != nil {
remoteFile.Close()
localFile.Close()
continue
}
if err := ftp.Conn.Remove(remoteFilePath); err != nil {
continue
}
}

Go SMB2 , reading and listing directory

I'm trying to list directory contents on a share from Linux to Windows using Go.
So far I've managed to Create/Remove new files inside a share with full Read/Write permissions.
Go module: https://godoc.org/github.com/hirochachacha/go-smb2#Client
Functions:
func connect_client(host string, share string, session map[string]string) *smb2.Client {
//Checks for a connection on port
conn, err := net.Dial("tcp", host+":445")
if err != nil {
panic(err)
}
//smb auth
d := &smb2.Dialer{
Initiator: &smb2.NTLMInitiator{
User: session["Username"],
Password: session["Password"],
Domain: session["Domain"],
},
}
//Returns a client session
client, err := d.Dial(conn)
if err != nil {
fmt.Println("Connection failed")
client.Logoff()
} else {
fmt.Println("Connection Succeeded")
}
return client
}
func check_write(host string, client *smb2.Client) {
file := "asdasdas.txt"
fs, err := client.Mount(host)
if err != nil {
fmt.Println(err)
os.Exit(0)
}
defer fs.Umount()
share := strings.Split(host, `\\`)
f, err := fs.Create(file)
if err != nil {
fmt.Println("You do not have write permissions on directory:%s ! \n", strings.Split(share[1], `\`)[1])
os.Exit(0)
}
defer fs.Remove(file)
defer f.Close()
fmt.Printf("You have write permissions to directory: %s \n", strings.Split(share[1], `\`)[1]))
}
func list_all(client *smb2.Client, host string) {
fs, err := client.Mount(host)
if err != nil {
fmt.Println(err)
os.Exit(0)
}
defer fs.Umount()
_, err = fs.Open(`Test.txt`)
if err != nil {
fmt.Println(err)
os.Exit(0)
}
}
func main() {
host, share, action, session := get_flags()
client := connect_client(host, share, session)
full_host := `\\` + host + `\` + share
//File create
if action == "check_write" {
check_write(full_host, client)
}
if action == "list_files" {
list_all(client, full_host)
}
}
In the function list_all() everything works, but when I am trying to access \\192.168.1.19\Sharing only..
When I input just a host with directory name it seas it can not list the directory path because it can not find the object specified.
I can't understand how I can get pointer used for *RemoteFile in order to use the functions:
f.Readdir()
f.Name()
etc....
So far I managed to use *RemoteFileSystem only for all other actions but I want to list all contents of the directory..
Help would be much appreciated!
Edit:
If it wasn't clear enough, in order to use functions like:
f.Readdir()
f.Name()
I need to get a pointer for *RemoteFile, this is my main issue
https://godoc.org/github.com/hirochachacha/go-smb2#RemoteFileSystem.Open
Use Open on a RemoteFileSystem and either a directory name, or empty string for the directory at the root of the filesystem.
e.g.
client, err := d.Dial(conn)
if err != nil {
return err
}
rfs, err := client.Mount("jrwren")
if err != nil {
return err
}
// cat the NOTES file.
f, err := rfs.Open("NOTES")
if err != nil {
return err
}
defer f.Close()
io.Copy(os.Stdout, f)
// List all the files
dir, err := rfs.Open("")
if err != nil {
return err
}
fis, err := dir.Readdir(10)
if err != nil {
return err
}
for i := range fis {
fmt.Println(fis[i].Name())
}
func list_all(client *smb2.Client, host string) {
fs, err := client.Mount(host)
if err != nil {
fmt.Println(err)
os.Exit(0)
}
dir, err := fs.Open("")
if err != nil {
fmt.Println(err)
os.Exit(0)
}
fis, err := dir.Readdir(-1)
if err != nil {
fmt.Println(err)
os.Exit(0)
}
for i := range fis {
fmt.Println(fis[i].Name())
}
}
This would be the answer thank you!

GO zip.NewWriter() creating empty zip archives

I have the following function I'v tried to simplify to just adding a single file to a .zip archive.
Whatever I try, the resulting .zip file has no files listed in it. The size of the archive is correct. But when I try to extract all (windows), the archive is empty.
go version go1.10.1 windows/amd64
func Zip(src string, dst string) error {
destinationFile, err := os.Create(dst)
if err != nil {
return err
}
myZip := zip.NewWriter(destinationFile)
file := `C:\MA\testing\cldeploy-local.json`
zipFile, err := myZip.Create(file)
fsFile, err := os.Open(file)
if err != nil {
return err
}
_, err = io.Copy(zipFile, fsFile)
if err != nil {
return err
}
return nil
if err != nil {
return err
}
err = myZip.Close()
if err != nil {
return err
}
return nil
}
When I extract the file an error message appears: The compressed (zipped) Folder ... is invalid.
As answered by #JimB: file needs to be added as relative path
only forward slashes. can not start with slash
func Zip(src string, dst string) error {
destinationFile, err := os.Create(dst)
if err != nil {
return err
}
myZip := zip.NewWriter(destinationFile)
file := `C:\MA\testing\cldeploy-local.json`
// file needs to be added as relative path
// only forward slashes. can not start with slash
relPath := strings.TrimPrefix(file, filepath.Dir(src))
relPath = strings.Replace(relPath, `\`, `/`, -1)
relPath = strings.TrimLeft(relPath, `/`)
zipFile, err := myZip.Create(relPath)
fsFile, err := os.Open(file)
if err != nil {
return err
}
_, err = io.Copy(zipFile, fsFile)
if err != nil {
return err
}
return nil
if err != nil {
return err
}
err = myZip.Close()
if err != nil {
return err
}
return nil
}
I faced same issue.
Zipfile created, but empty if you open it with Windows Explorer. But if you open it with 7-zip filename looks like
Actual:
C:\Users\user\AppData\Local\Temp\products_list_432735630.zip\C:\Users\user\AppData\Local\Temp
Expected
C:\Users\user\AppData\Local\Temp\products_list_432735630.zip\
So if zip file and CSV file in one folder you must use relative path.
For Example
relativeFilename := filepath.Base(csvFile.Name())
zippedFile, err := zipper.Create(relativeFilename)

Unable to delete an unzipped folder using golang

I wrote code that unzips a file in a particular location then copies the contents of the folder to outside where the folder is unzipped then it removes the folder.
This is the Code I wrote:
package main
import (
"os"
"flag"
"fmt"
"io"
"path/filepath"
"os/exec"
"archive/zip"
"time"
)
func RemoveContents(dir string) error {
d, err := os.Open(dir)
if err != nil {
return err
}
names, err := d.Readdirnames(-1)
if err != nil {
return err
}
for _, name := range names {
err = os.RemoveAll(filepath.Join(dir, name))
if err != nil {
return err
}
}
d.Close()
return nil
}
func CopyFile(source string, dest string) (err error) {
sourcefile, err := os.Open(source)
if err != nil {
return err
}
defer sourcefile.Close()
destfile, err := os.Create(dest)
if err != nil {
return err
}
defer destfile.Close()
_, err = io.Copy(destfile, sourcefile)
if err == nil {
sourceinfo, err := os.Stat(source)
if err != nil {
err = os.Chmod(dest, sourceinfo.Mode())
}
}
return
}
func CopyDir(source string, dest string) (err error) {
// get properties of source dir
sourceinfo, err := os.Stat(source)
if err != nil {
return err
}
// create dest dir
err = os.MkdirAll(dest, sourceinfo.Mode())
if err != nil {
return err
}
directory, _ := os.Open(source)
objects, err := directory.Readdir(-1)
for _, obj := range objects {
sourcefilepointer := source + "/" + obj.Name()
destinationfilepointer := dest + "/" + obj.Name()
if obj.IsDir() {
// create sub-directories - recursively
err = CopyDir(sourcefilepointer, destinationfilepointer)
if err != nil {
fmt.Println(err)
}
} else {
// perform copy
err = CopyFile(sourcefilepointer, destinationfilepointer)
if err != nil {
fmt.Println(err)
}
}
}
return
}
func main() {
flag.Parse() // get the source and destination directory
source_dir := flag.Arg(0) // get the source directory from 1st argument
dest_dir := flag.Arg(1) // get the destination directory from the 2nd argument
os.MkdirAll("E:\\go\\copyDirectory\\myFile.zip",0777)
zipFilePath := "E:\\go\\copyDirectory\\myFile.zip"
tempWrkDir := "E:\\go\\copyDirectory\\"
//Read zip file and get path handle.
fileHandleReader, err := zip.OpenReader(zipFilePath)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
//open zip file and read all the folder and files inside
for _, fileReadHandler := range fileHandleReader.Reader.File {
//read the file or folder handle inside zip
fileOpenHandle, err := fileReadHandler.Open()
if err != nil {
fmt.Println(err)
os.Exit(1)
}
defer fileOpenHandle.Close()
targetUnZipPath := filepath.Join(tempWrkDir, fileReadHandler.Name)
if fileReadHandler.FileInfo().IsDir() {
os.MkdirAll(targetUnZipPath, fileReadHandler.Mode())
//fmt.Println("Creating directory", path)
}else {
// create new dummy file to copy original file.
newTempFileHandle, err := os.OpenFile(targetUnZipPath, os.O_WRONLY|os.O_CREATE, fileReadHandler.Mode())
if err != nil {
fmt.Println(err)
os.Exit(1)
}
defer newTempFileHandle.Close()
//copying original file to dummy file.
if _, err = io.Copy(newTempFileHandle, fileOpenHandle); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
}
time.Sleep(1000*time.Millisecond)
fmt.Println("Source :" + source_dir)
// check if the source dir exist
src, err := os.Stat(source_dir)
if err != nil {
panic(err)
}
if !src.IsDir() {
fmt.Println("Source is not a directory")
os.Exit(1)
}
// create the destination directory
fmt.Println("Destination :"+ dest_dir)
/*_, err = os.Open(dest_dir)
if !os.IsNotExist(err) {
fmt.Println("Destination directory already exists. Abort!")
os.Exit(1)
}*/
err = CopyDir(source_dir, dest_dir)
if err != nil {
fmt.Println(err)
} else {
fmt.Println("Directory copied")
}
err = RemoveContents("./myFiles")
if err != nil {
fmt.Println("ERRR:::",err)
}
//time.Sleep(10000*time.Millisecond)
}
The problem is that everything works fine except for deleting the folder. The folder has only one file in it. The location of the file is as follows:
E:\go\copyDirectory\myfile\mytextfile.txt
The Location of the zip file is as follows:
E:\go\copyDirectory\myfile.zip
The zip file has only one text file. The File inside the zip file is as follows:
E:\go\copyDirectory\myfile.zip\myfile\mytextfile.txt
The error I get is:
ERRR::: remove myfile\mytextfile.txt: The process cannot
access the file because it is being used by another process.
Thanks in advance.
You aren't closing the file. This:
defer newTempFileHandle.Close()
Is run when main finishes, which is after:
err = RemoveContents("./myFiles")
You can wrap that bit of code in an unnamed function:
func() {
//read the file or folder handle inside zip
fileOpenHandle, err := fileReadHandler.Open()
if err != nil {
fmt.Println(err)
os.Exit(1)
}
defer fileOpenHandle.Close()
targetUnZipPath := filepath.Join(tempWrkDir, fileReadHandler.Name)
if fileReadHandler.FileInfo().IsDir() {
os.MkdirAll(targetUnZipPath, fileReadHandler.Mode())
//fmt.Println("Creating directory", path)
} else {
// create new dummy file to copy original file.
newTempFileHandle, err := os.OpenFile(targetUnZipPath, os.O_WRONLY|os.O_CREATE, fileReadHandler.Mode())
if err != nil {
fmt.Println(err)
os.Exit(1)
}
defer newTempFileHandle.Close()
//copying original file to dummy file.
if _, err = io.Copy(newTempFileHandle, fileOpenHandle); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
}()
And then your defer will happen before you try and remove the files. I would recommend pulling this out into a named function though.

Resources