Skip to content

Commit d7b53f2

Browse files
authored
Allow moving file to a destination without write permissions (#71)
1 parent 2cc911a commit d7b53f2

File tree

2 files changed

+89
-2
lines changed

2 files changed

+89
-2
lines changed

io/fileutils.go

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ import (
1717
"strconv"
1818
"strings"
1919
"time"
20+
21+
"github.com/jfrog/gofrog/log"
2022
)
2123

2224
const (
@@ -325,8 +327,7 @@ func MoveFile(sourcePath, destPath string) (err error) {
325327
return
326328
}
327329

328-
var outputFile *os.File
329-
outputFile, err = os.Create(destPath)
330+
outputFile, err := createFileForWriting(destPath)
330331
if err != nil {
331332
return
332333
}
@@ -353,6 +354,25 @@ func MoveFile(sourcePath, destPath string) (err error) {
353354
return
354355
}
355356

357+
// Create file for writing. If file already exists, it will be truncated.
358+
// If the file exists and is read-only, the function will try to change the file permissions to read-write.
359+
// The caller should update the permissions and close the file when done.
360+
func createFileForWriting(destPath string) (*os.File, error) {
361+
// Try to create the destination file
362+
outputFile, err := os.Create(destPath)
363+
if err == nil {
364+
return outputFile, nil
365+
}
366+
367+
log.Debug(fmt.Sprintf("Couldn't to open the destination file: '%s' due to %s. Attempting to set the file permissions to read-write.", destPath, err.Error()))
368+
if chmodErr := os.Chmod(destPath, 0600); chmodErr != nil {
369+
return nil, errors.Join(err, chmodErr)
370+
}
371+
372+
// Try to open the destination file again
373+
return os.Create(destPath)
374+
}
375+
356376
// Return the list of files and directories in the specified path
357377
func ListFiles(path string, includeDirs bool) ([]string, error) {
358378
sep := GetFileSeparator()

io/fileutils_test.go

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,3 +93,70 @@ func TestCreateTempDir(t *testing.T) {
9393
assert.NoError(t, os.RemoveAll(tempDir))
9494
}()
9595
}
96+
97+
func TestMoveFile_New(t *testing.T) {
98+
// Init test
99+
sourcePath, destPath := initMoveTest(t)
100+
101+
// Move file
102+
assert.NoError(t, MoveFile(sourcePath, destPath))
103+
104+
// Assert expected file paths
105+
assert.FileExists(t, destPath)
106+
assert.NoFileExists(t, sourcePath)
107+
}
108+
109+
func TestMoveFile_Override(t *testing.T) {
110+
// Init test
111+
sourcePath, destPath := initMoveTest(t)
112+
err := os.WriteFile(destPath, []byte("dst"), 0600)
113+
assert.NoError(t, err)
114+
115+
// Move file
116+
assert.NoError(t, MoveFile(sourcePath, destPath))
117+
118+
// Assert file overidden
119+
assert.FileExists(t, destPath)
120+
destFileContent, err := os.ReadFile(destPath)
121+
assert.NoError(t, err)
122+
assert.Equal(t, "src", string(destFileContent))
123+
124+
// Assert source file removed
125+
assert.NoFileExists(t, sourcePath)
126+
}
127+
128+
func TestMoveFile_NoPerm(t *testing.T) {
129+
// Init test
130+
sourcePath, destPath := initMoveTest(t)
131+
err := os.WriteFile(destPath, []byte("dst"), 0600)
132+
assert.NoError(t, err)
133+
134+
// Remove all permissions from destination file
135+
assert.NoError(t, os.Chmod(destPath, 0000))
136+
_, err = os.Create(destPath)
137+
assert.Error(t, err)
138+
139+
// Move file
140+
assert.NoError(t, MoveFile(sourcePath, destPath))
141+
142+
// Assert file overidden
143+
assert.FileExists(t, destPath)
144+
destFileContent, err := os.ReadFile(destPath)
145+
assert.NoError(t, err)
146+
assert.Equal(t, "src", string(destFileContent))
147+
148+
// Assert source file removed
149+
assert.NoFileExists(t, sourcePath)
150+
}
151+
152+
func initMoveTest(t *testing.T) (sourcePath, destPath string) {
153+
// Create source and destination paths
154+
tmpDir := t.TempDir()
155+
sourcePath = filepath.Join(tmpDir, "src")
156+
destPath = filepath.Join(tmpDir, "dst")
157+
158+
// Write content to source file
159+
err := os.WriteFile(sourcePath, []byte("src"), 0600)
160+
assert.NoError(t, err)
161+
return
162+
}

0 commit comments

Comments
 (0)