How to create a hidden file in Windows/Mac/Linux? - go

I build an console application, need create some hidden files.
As well I know filename start with dot will hidden in Linux and mac, but windows?
Set file attributes?
Is there a way to create hidden files and directories in both Windows / Linux / Mac?

Windows:
SetFileAttributesW function
Sets the attributes for a file or directory.
FILE_ATTRIBUTE_HIDDEN 2 (0x2)
The file or directory is hidden. It is not included in an ordinary
directory listing.
Go:
Package syscall
func SetFileAttributes
func SetFileAttributes(name *uint16, attrs uint32) (err error)
Convert from a Go UTF-8 encoded string (string) to a Windows UTF-16 encoded string pointer (*uint16).
Package syscall
func UTF16PtrFromString
func UTF16PtrFromString(s string) (*uint16, error)
UTF16PtrFromString returns pointer to the UTF-16 encoding of the UTF-8
string s, with a terminating NUL added. If s contains a NUL byte at
any location, it returns (nil, EINVAL).
Use OS Build Contraints.
For example,
hide/attrib.go:
package main
import (
"fmt"
"io/ioutil"
"os"
)
func main() {
filename := `test.hidden.file`
os.Remove(filename)
os.Remove("." + filename)
err := ioutil.WriteFile(filename, []byte(filename), 0666)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
err = HideFile(filename)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
fmt.Println("hidden:", filename)
}
hide/hide.go:
// +build !windows
package main
import (
"os"
"path/filepath"
"strings"
)
func HideFile(filename string) error {
if !strings.HasPrefix(filepath.Base(filename), ".") {
err := os.Rename(filename, "."+filename)
if err != nil {
return err
}
}
return nil
}
hide/hide_windows.go:
// +build windows
package main
import (
"syscall"
)
func HideFile(filename string) error {
filenameW, err := syscall.UTF16PtrFromString(filename)
if err != nil {
return err
}
err = syscall.SetFileAttributes(filenameW, syscall.FILE_ATTRIBUTE_HIDDEN)
if err != nil {
return err
}
return nil
}
Output (Linux):
$ tree hide
hide
├── attrib.go
├── hide.go
└── hide_windows.go
$
$ go build && ./hide
hidden: test.hidden.file
$ ls -a .test.hidden.file
.test.hidden.file
$
Output (Windows):
>go build && hide
hidden: test.hidden.file
>attrib test.hidden.file
A H \test.hidden.file
>

I made a cross-platform module for this (it's available here: higgs).
You can hide or unhide file or directory simply by calling Hide or Unhide functions.
Sample code:
package main
import (
"fmt"
"github.com/dastoori/higgs"
)
func main() {
err := higgs.Hide("foo.txt")
if err != nil {
fmt.Println(err)
}
}

Make a file like this:
//go:generate mkwinsyscall -output zhide.go hide.go
//sys setFileAttributes(name string, attr int) (err error) = kernel32.SetFileAttributesW
package main
const (
file_attribute_hidden = 2
file_attribute_normal = 128
)
func main() {
setFileAttributes("file.txt", file_attribute_hidden)
}
Then build:
go mod init hide
go mod tidy
go generate
go build

import (
_ "golang.org/x/sys/windows"
"os"
"runtime"
"syscall"
)
func HideFile(filename string) (status bool, err error) {
if runtime.GOOS == "windows" {
filenameW, err := syscall.UTF16PtrFromString(filename)
if err != nil {
return false, err
}
err = syscall.SetFileAttributes(filenameW, syscall.FILE_ATTRIBUTE_HIDDEN)
if err != nil {
return false, err
}
} else {
if filename[0:1] != "." {
err = os.Rename(filename, "." + filename)
if err != nil {
return false, err
}
}
}
return true, nil
}
That's my code. But can't build in Linux。
Errors:
src/util/hidden.go:12:21: undefined: syscall.UTF16PtrFromString
src/util/hidden.go:17:9: undefined: syscall.SetFileAttributes
src/util/hidden.go:17:46: undefined: syscall.FILE_ATTRIBUTE_HIDDEN

Related

Check if the program is running and stop more than one [duplicate]

I need to only allow one instance of my Golang executable at a time. I'm not sure how to use a Global Mutex to make sure no other instances are running.
This would be running on a Windows Machine.
I know this topic is a bit old, but I needed it recently on Windows and I'll post here how I did it in case someone else needs.
Thx to #VonC for pointing me in the right direction.
var (
kernel32 = syscall.NewLazyDLL("kernel32.dll")
procCreateMutex = kernel32.NewProc("CreateMutexW")
)
func CreateMutex(name string) (uintptr, error) {
ret, _, err := procCreateMutex.Call(
0,
0,
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(name))),
)
switch int(err.(syscall.Errno)) {
case 0:
return ret, nil
default:
return ret, err
}
}
// mutexName starting with "Global\" will work across all user sessions
_, err := CreateMutex("SomeMutexName")
I created a lib with a more complete example: https://github.com/rodolfoag/gow32
Thx!
There doesn't seem to be a cross-platform solution (beside writing a file, and looking for that file at start time).
On Windows, this thread reports
the recommended approach (and the one that has worked great for me) is to use the CreateSemaphore function.
If the name you specify starts with "Global\", then the semaphore is unique for the entire system and a second attempt to open it will fail.
This is a kernel32 call, which has some wrapper in Go available.
kostix adds in the comments:
look at the Go source code around the pkg\syscall hierarchy -- it contains a good wealth of examples on how to call out to DLLs on Windows using syscalls (and that's how you access anything in Windows API).
That would be syscall/dll_windows.go. (And here is a gist)
The odbc package by brainman is another example of direct API calls on Windows -- possibly easier to digest.
Like api/zapi_windows.go.
You could use sockets, simple to use and will work on everything really.
package main
import (
"fmt"
"net"
"os"
"strings"
)
const (
INSTANCE_PORT = 9292
)
func main() {
listener, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", INSTANCE_PORT))
if err != nil {
if strings.Index(err.Error(), "in use") != -1 {
//optionally send command line arguments to the other instance
fmt.Fprintln(os.Stderr, "Already running.")
return
} else {
panic(err)
}
}
for {
conn, err := listener.Accept()
if err != nil {
println("Error accept:", err.Error())
return
}
go do_something_with(conn)
}
}
You could adapt the code from tendo's python library source
what they do is
for windows :
creating a file made of the executable absolute path (well it's a library, so in your case, you can just define an identifier, to prevent you from "i put the executable in 2 places")
For windows: trying first to remove the file if existing, and if not creating the file with os.O_CREAT | os.O_EXCL | os.O_RDWR
For POSIX compatible systems: trying first to remove the file if existing and if not creating the file and acquiring a lock on it using fcntl.LOCK_EX | fcntl.LOCK_NB
any failure mean the program is already running
and then you can use a defer action to remove the lock (on posix system) and delete the file
Go permit you to create both version wit a build comment to tell which file to compile depending on your OS so you have
for unix system
// +build !windows
package main
import (
"os"
"syscall"
)
func create_lock_file(filename string) (*os.File, error) {
file, err := os.OpenFile(filename, os.O_WRONLY, 0666)
if err != nil {
return nil, err
}
err = syscall.Flock(int(file.Fd()), syscall.LOCK_EX|syscall.LOCK_NB)
if err != nil {
return nil, err
}
return file, nil
}
for windows:
// +build !windows
package main
import (
"os"
)
func create_lock_file(filename string) (*os.File, error) {
if _, err := os.Stat(filename); err == nil {
err = os.Remove(filename)
if err != nil {
return nil, err
}
}
return os.OpenFile(filename, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0666)
}
and a test
package main
import (
"fmt"
"time"
)
func main() {
_, err := create_lock_file("plop.lock")
if err != nil {
fmt.Println("error ", err.Error())
}
time.Sleep(10 * time.Second)
fmt.Println("end ")
}
I've started a library out of it that you can find here
Improvements to this answer. (I am unsure if this answer will distort the original meaning, so I have written a new answer.)
Features:
deprecated: StringToUTF16Ptr is deprecated. Use UTF16PtrFromString instead.
Add the CloseHandle so that you can cancel the CreateMutexW.
package _test
import (
"syscall"
"testing"
"unsafe"
)
var (
kernel32 = syscall.NewLazyDLL("kernel32.dll")
procCreateMutexW = kernel32.NewProc("CreateMutexW")
procCloseHandle = kernel32.NewProc("CloseHandle")
)
// https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-createmutexW#return-value
func CreateMutexW(proc *syscall.LazyProc, name string) (uintptr, error) {
if proc.Name != "CreateMutexW" {
panic("proc.Name != CreateMutexW")
}
lpName, _ := syscall.UTF16PtrFromString(name) // LPCWSTR
if handleID, _, err := proc.Call(
0,
0,
uintptr(unsafe.Pointer(lpName)),
); err.(syscall.Errno) == 0 {
return handleID, nil
} else {
return handleID, err
}
}
// https://learn.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-closehandle?redirectedfrom=MSDN
func CloseHandle(proc *syscall.LazyProc, handle uintptr) error {
if proc.Name != "CloseHandle" {
panic("proc.Name != CloseHandle")
}
val, _, err := proc.Call(handle)
if val == 0 {
return err
}
return nil
}
func TestCreateMutexW(t *testing.T) {
handle, err := CreateMutexW(procCreateMutexW, "hello world")
if err != nil {
t.Fatalf(err.Error())
}
_, err = CreateMutexW(procCreateMutexW, "hello world")
if err == nil || err != syscall.ERROR_ALREADY_EXISTS {
t.Error("should panic")
}
if err = CloseHandle(procCloseHandle, handle); err != nil {
t.Error(err)
}
// We can create again since we have closed.
handle, _ = CreateMutexW(procCreateMutexW, "hello world")
if err = CloseHandle(procCloseHandle, handle); err != nil {
t.Error(err)
}
}

Copy files into a folder until it reaches a certain size

I have a folder named "myfolder" that has some txt and jpeg files and and a folder named "test".
I want to copy files inside myfolder to test until it reaches a certain size, for example 10MB, then stop to copy.
This is my code that does not work:
package main
import (
"errors"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strconv"
)
var (
MyFolderPath = "/home/jim/myfolder"
files []string
)
func copy(source []string, destination string) {
for a, b := range source {
input, _ := ioutil.ReadFile(b)
ioutil.WriteFile(destination+strconv.Itoa(a), input, 0777)
}
}
func CopyFile(path string) {
var size int64
done := errors.New("size reached")
err := filepath.Walk(path, func(_ string, info os.FileInfo, err error) error {
if err != nil {
return err
}
copy(files[1:], fmt.Sprintf("%v/test/%v", MyFolderPath, "file"))
size += info.Size()
if size > 10000 {
return done
}
return err
})
if err != nil {
fmt.Println(err)
}
}
func CollectFiles() {
err := filepath.Walk(MyFolderPath, func(path string, info os.FileInfo, err error) error {
if err != nil {
fmt.Println(err)
}
files = append(files, path)
return nil
})
if err != nil {
fmt.Println(err)
}
}
func main() {
CollectFiles()
CopyFile(fmt.Sprintf("%v/test", MyFolderPath))
}
What I do wrong and how can I do in right way?
This line is wrong:
copy(files[1:], fmt.Sprintf("%v/test/%v", MyFolderPath, "file"))
Every time you find a file match, you tell it to (re)-copy every file in your files slice, except the first one.
You probably want to copy a single file there.
Although your code is difficult to reason through--I'm not sure why files exists at all, nor why you're walking your directory structure twice. So your goals aren't really clear, so it's hard to be more specific.
Also note: You should not use copy as the name of a function, as that is a built-in, so makes your code very confusing to read.
You have multiple places where you're wrong. Perhaps check this code and compare:
package main
import (
"errors"
"fmt"
"os"
"path/filepath"
)
var (
MyFolderPath = "/tmp"
DestPath = "/tmp/dest"
CumulativeSize int64 = 0 // in bytes
ErrDone = errors.New("done")
)
const UpperLimit = 1024 * // 1 Kilobyte
1024 * // 1 Megabyte
10 // 10 Megabytes
func main() {
err := filepath.Walk(MyFolderPath, func(path string, info os.FileInfo, err error) error {
if err != nil {
fmt.Printf("problem with file (%s): %v", path, err)
return nil
}
if info.IsDir() {
return filepath.SkipDir // skip it, walk will enter it too
}
CumulativeSize += info.Size()
if CumulativeSize >= UpperLimit {
return ErrDone
}
// copy file here
return nil
})
if err == ErrDone {
fmt.Println("finished successfully")
} else {
fmt.Printf("error: %v", err)
}
}

How to create new file using go script

I am new to go lang. I am able to create a new file from the terminal using go script. like this
go run ../myscript.go > ../filename.txt
but I want to create the file from the script.
package main
import "fmt"
func main() {
fmt.Println("Hello") > filename.txt
}
If you are trying to print some text to a file one way to do it is like below, however if the file already exists its contents will be lost:
package main
import (
"fmt"
"os"
)
func main() {
err := os.WriteFile("filename.txt", []byte("Hello"), 0755)
if err != nil {
fmt.Printf("Unable to write file: %v", err)
}
}
The following way will allow you to append to an existing file if it already exists, or creates a new file if it doesn't exist:
package main
import (
"os"
"log"
)
func main() {
// If the file doesn't exist, create it, or append to the file
f, err := os.OpenFile("access.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
log.Fatal(err)
}
_, err = f.Write([]byte("Hello"))
if err != nil {
log.Fatal(err)
}
f.Close()
}
you just need to check the API documentation. This is one way to do it, there is others (with os or bufio)
package main
import (
"io/ioutil"
)
func main() {
// read the whole file at once
b, err := ioutil.ReadFile("input.txt")
if err != nil {
panic(err)
}
// write the whole body at once
err = ioutil.WriteFile("output.txt", b, 0644)
if err != nil {
panic(err)
}
}
Fprintln is pretty close to what you were trying to do:
package main
import (
"fmt"
"os"
)
func main() {
f, e := os.Create("filename.txt")
if e != nil {
panic(e)
}
defer f.Close()
fmt.Fprintln(f, "Hello")
}
https://golang.org/pkg/fmt#Fprintln

How to call Go function of test1 in test2

go file in as below
package goClientLib
import (
....
)
//The following function will read Command Line Inputs and will return 3 strings
func readInput() (string, string, string){
var (clientRequest, clientId, clientPassword string)
argsLen := len(os.Args)
fmt.Println("Arg Length:",argsLen)
if len(os.Args) != 4 {
fmt.Fprintf(os.Stderr, "Usage: %s URL\n", os.Args[0])
os.Exit(1)
} else {
clientRequest = strings.Join(os.Args[1:2],"")
clientId = strings.Join(os.Args[2:3],"")
clientPassword = strings.Join(os.Args[3:4],"")
}
return clientRequest, clientId, clientPassword
}
Now I am trying to use it in Test2.go file as shown below:
package main
import (
"os"
"fmt"
"net/http"
"io"
"log"
"goClientLib"
)
func main() {
clientRequest, clientId, clientPassword := goClientLib.readInput()
host := goClientLib.generateRequest(clientRequest)
fmt.Println("clientRequest:",clientRequest)
fmt.Println("clientId:",clientId)
fmt.Println("clientPassword:",clientPassword)
fmt.Println("host:",host)
response, err := http.Get(host)
if err != nil {
log.Fatal(err)
} else {
defer response.Body.Close()
_, err := io.Copy(os.Stdout, response.Body)
if err != nil {
log.Fatal(err)
}
}
}
I am using Following File Structure
src/test2.go
src/goClientLib/test1.go
But This code Give me following error while running
# command-line-arguments
src\goClientMain.go:15: cannot refer to unexported name goClientLib.readInput
src\goClientMain.go:16: cannot refer to unexported name goClientLib.generateRequest
src\goClientMain.go:16: undefined: goClientLib.generateRequest
As Volker commented, in order to access functions from another package, 1st letter of function name must be capital. In your case, change readInput() to ReadInput() and generateRequest() to GenerateRequest() and make sure GenerateRequest() function is defined in goClientLib package. Chack this for more information.

Restricting to Single Instance of Executable with Golang

I need to only allow one instance of my Golang executable at a time. I'm not sure how to use a Global Mutex to make sure no other instances are running.
This would be running on a Windows Machine.
I know this topic is a bit old, but I needed it recently on Windows and I'll post here how I did it in case someone else needs.
Thx to #VonC for pointing me in the right direction.
var (
kernel32 = syscall.NewLazyDLL("kernel32.dll")
procCreateMutex = kernel32.NewProc("CreateMutexW")
)
func CreateMutex(name string) (uintptr, error) {
ret, _, err := procCreateMutex.Call(
0,
0,
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(name))),
)
switch int(err.(syscall.Errno)) {
case 0:
return ret, nil
default:
return ret, err
}
}
// mutexName starting with "Global\" will work across all user sessions
_, err := CreateMutex("SomeMutexName")
I created a lib with a more complete example: https://github.com/rodolfoag/gow32
Thx!
There doesn't seem to be a cross-platform solution (beside writing a file, and looking for that file at start time).
On Windows, this thread reports
the recommended approach (and the one that has worked great for me) is to use the CreateSemaphore function.
If the name you specify starts with "Global\", then the semaphore is unique for the entire system and a second attempt to open it will fail.
This is a kernel32 call, which has some wrapper in Go available.
kostix adds in the comments:
look at the Go source code around the pkg\syscall hierarchy -- it contains a good wealth of examples on how to call out to DLLs on Windows using syscalls (and that's how you access anything in Windows API).
That would be syscall/dll_windows.go. (And here is a gist)
The odbc package by brainman is another example of direct API calls on Windows -- possibly easier to digest.
Like api/zapi_windows.go.
You could use sockets, simple to use and will work on everything really.
package main
import (
"fmt"
"net"
"os"
"strings"
)
const (
INSTANCE_PORT = 9292
)
func main() {
listener, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", INSTANCE_PORT))
if err != nil {
if strings.Index(err.Error(), "in use") != -1 {
//optionally send command line arguments to the other instance
fmt.Fprintln(os.Stderr, "Already running.")
return
} else {
panic(err)
}
}
for {
conn, err := listener.Accept()
if err != nil {
println("Error accept:", err.Error())
return
}
go do_something_with(conn)
}
}
You could adapt the code from tendo's python library source
what they do is
for windows :
creating a file made of the executable absolute path (well it's a library, so in your case, you can just define an identifier, to prevent you from "i put the executable in 2 places")
For windows: trying first to remove the file if existing, and if not creating the file with os.O_CREAT | os.O_EXCL | os.O_RDWR
For POSIX compatible systems: trying first to remove the file if existing and if not creating the file and acquiring a lock on it using fcntl.LOCK_EX | fcntl.LOCK_NB
any failure mean the program is already running
and then you can use a defer action to remove the lock (on posix system) and delete the file
Go permit you to create both version wit a build comment to tell which file to compile depending on your OS so you have
for unix system
// +build !windows
package main
import (
"os"
"syscall"
)
func create_lock_file(filename string) (*os.File, error) {
file, err := os.OpenFile(filename, os.O_WRONLY, 0666)
if err != nil {
return nil, err
}
err = syscall.Flock(int(file.Fd()), syscall.LOCK_EX|syscall.LOCK_NB)
if err != nil {
return nil, err
}
return file, nil
}
for windows:
// +build !windows
package main
import (
"os"
)
func create_lock_file(filename string) (*os.File, error) {
if _, err := os.Stat(filename); err == nil {
err = os.Remove(filename)
if err != nil {
return nil, err
}
}
return os.OpenFile(filename, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0666)
}
and a test
package main
import (
"fmt"
"time"
)
func main() {
_, err := create_lock_file("plop.lock")
if err != nil {
fmt.Println("error ", err.Error())
}
time.Sleep(10 * time.Second)
fmt.Println("end ")
}
I've started a library out of it that you can find here
Improvements to this answer. (I am unsure if this answer will distort the original meaning, so I have written a new answer.)
Features:
deprecated: StringToUTF16Ptr is deprecated. Use UTF16PtrFromString instead.
Add the CloseHandle so that you can cancel the CreateMutexW.
package _test
import (
"syscall"
"testing"
"unsafe"
)
var (
kernel32 = syscall.NewLazyDLL("kernel32.dll")
procCreateMutexW = kernel32.NewProc("CreateMutexW")
procCloseHandle = kernel32.NewProc("CloseHandle")
)
// https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-createmutexW#return-value
func CreateMutexW(proc *syscall.LazyProc, name string) (uintptr, error) {
if proc.Name != "CreateMutexW" {
panic("proc.Name != CreateMutexW")
}
lpName, _ := syscall.UTF16PtrFromString(name) // LPCWSTR
if handleID, _, err := proc.Call(
0,
0,
uintptr(unsafe.Pointer(lpName)),
); err.(syscall.Errno) == 0 {
return handleID, nil
} else {
return handleID, err
}
}
// https://learn.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-closehandle?redirectedfrom=MSDN
func CloseHandle(proc *syscall.LazyProc, handle uintptr) error {
if proc.Name != "CloseHandle" {
panic("proc.Name != CloseHandle")
}
val, _, err := proc.Call(handle)
if val == 0 {
return err
}
return nil
}
func TestCreateMutexW(t *testing.T) {
handle, err := CreateMutexW(procCreateMutexW, "hello world")
if err != nil {
t.Fatalf(err.Error())
}
_, err = CreateMutexW(procCreateMutexW, "hello world")
if err == nil || err != syscall.ERROR_ALREADY_EXISTS {
t.Error("should panic")
}
if err = CloseHandle(procCloseHandle, handle); err != nil {
t.Error(err)
}
// We can create again since we have closed.
handle, _ = CreateMutexW(procCreateMutexW, "hello world")
if err = CloseHandle(procCloseHandle, handle); err != nil {
t.Error(err)
}
}

Resources