From 8bd6e1d119b16a63f11309ecac41ce1433566ca9 Mon Sep 17 00:00:00 2001 From: luoliwoshang <2643523683@qq.com> Date: Mon, 12 Aug 2024 21:36:29 +0800 Subject: [PATCH 1/2] lib/os: patch MkdirAll --- _demo/mkdirdemo/mkdir.go | 11 ++++ internal/lib/internal/filepathlite/path.go | 53 ++++++++++++++++ .../lib/internal/filepathlite/path_unix.go | 30 +++++++++ internal/lib/internal/stringslite/strings.go | 17 +++++ internal/lib/os/os.go | 1 - internal/lib/os/path.go | 63 +++++++++++++++++++ 6 files changed, 174 insertions(+), 1 deletion(-) create mode 100644 _demo/mkdirdemo/mkdir.go create mode 100644 internal/lib/internal/filepathlite/path.go create mode 100644 internal/lib/internal/filepathlite/path_unix.go create mode 100644 internal/lib/internal/stringslite/strings.go create mode 100644 internal/lib/os/path.go diff --git a/_demo/mkdirdemo/mkdir.go b/_demo/mkdirdemo/mkdir.go new file mode 100644 index 000000000..cf9ea4cc5 --- /dev/null +++ b/_demo/mkdirdemo/mkdir.go @@ -0,0 +1,11 @@ +package main + +import ( + "os" + "path/filepath" +) + +func main() { + dirPath := filepath.Join("temp", "myapp", "data", "logs") + os.MkdirAll(dirPath, 0755) +} diff --git a/internal/lib/internal/filepathlite/path.go b/internal/lib/internal/filepathlite/path.go new file mode 100644 index 000000000..2aaed5337 --- /dev/null +++ b/internal/lib/internal/filepathlite/path.go @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package filepathlite + +import ( + "github.com/goplus/llgo/internal/lib/internal/stringslite" +) + +// FromSlash is filepath.ToSlash. +func FromSlash(path string) string { + if Separator == '/' { + return path + } + return replaceStringByte(path, '/', Separator) +} + +func replaceStringByte(s string, old, new byte) string { + if stringslite.IndexByte(s, old) == -1 { + return s + } + n := []byte(s) + for i := range n { + if n[i] == old { + n[i] = new + } + } + return string(n) +} + +// VolumeName is filepath.VolumeName. +func VolumeName(path string) string { + return FromSlash(path[:volumeNameLen(path)]) +} + +// VolumeNameLen returns the length of the leading volume name on Windows. +// It returns 0 elsewhere. +func VolumeNameLen(path string) int { + return volumeNameLen(path) +} diff --git a/internal/lib/internal/filepathlite/path_unix.go b/internal/lib/internal/filepathlite/path_unix.go new file mode 100644 index 000000000..e2f25598b --- /dev/null +++ b/internal/lib/internal/filepathlite/path_unix.go @@ -0,0 +1,30 @@ +//go:build unix || (js && wasm) || wasip1 + +/* + * Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package filepathlite + +const ( + Separator = '/' // OS-specific path separator + ListSeparator = ':' // OS-specific path list separator +) + +// volumeNameLen returns length of the leading volume name on Windows. +// It returns 0 elsewhere. +func volumeNameLen(path string) int { + return 0 +} diff --git a/internal/lib/internal/stringslite/strings.go b/internal/lib/internal/stringslite/strings.go new file mode 100644 index 000000000..4ad916cc9 --- /dev/null +++ b/internal/lib/internal/stringslite/strings.go @@ -0,0 +1,17 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package stringslite implements a subset of strings, +// only using packages that may be imported by "os". +// +// Tests for these functions are in the strings package. +package stringslite + +import ( + "github.com/goplus/llgo/internal/lib/internal/bytealg" +) + +func IndexByte(s string, c byte) int { + return bytealg.IndexByteString(s, c) +} diff --git a/internal/lib/os/os.go b/internal/lib/os/os.go index cf6099347..ebc0b46a3 100644 --- a/internal/lib/os/os.go +++ b/internal/lib/os/os.go @@ -271,7 +271,6 @@ func Mkdir(name string, perm FileMode) error { */ // TODO(xsw): -// func MkdirAll(path string, perm FileMode) error // func NewSyscallError(syscall string, err error) error // func ReadFile(name string) ([]byte, error) diff --git a/internal/lib/os/path.go b/internal/lib/os/path.go new file mode 100644 index 000000000..a0bbb7208 --- /dev/null +++ b/internal/lib/os/path.go @@ -0,0 +1,63 @@ +package os + +import ( + "syscall" + + "github.com/goplus/llgo/internal/lib/internal/filepathlite" +) + +// MkdirAll creates a directory named path, +// along with any necessary parents, and returns nil, +// or else returns an error. +// The permission bits perm (before umask) are used for all +// directories that MkdirAll creates. +// If path is already a directory, MkdirAll does nothing +// and returns nil. +func MkdirAll(path string, perm FileMode) error { + // Fast path: if we can tell whether path is a directory or file, stop with success or error. + dir, err := Stat(path) + if err == nil { + if dir.IsDir() { + return nil + } + return &PathError{Op: "mkdir", Path: path, Err: syscall.ENOTDIR} + } + + // Slow path: make sure parent exists and then call Mkdir for path. + + // Extract the parent folder from path by first removing any trailing + // path separator and then scanning backward until finding a path + // separator or reaching the beginning of the string. + i := len(path) - 1 + for i >= 0 && IsPathSeparator(path[i]) { + i-- + } + for i >= 0 && !IsPathSeparator(path[i]) { + i-- + } + if i < 0 { + i = 0 + } + + // If there is a parent directory, and it is not the volume name, + // recurse to ensure parent directory exists. + if parent := path[:i]; len(parent) > len(filepathlite.VolumeName(path)) { + err = MkdirAll(parent, perm) + if err != nil { + return err + } + } + + // Parent now exists; invoke Mkdir and use its result. + err = Mkdir(path, perm) + if err != nil { + // Handle arguments like "foo/." by + // double-checking that directory doesn't exist. + dir, err1 := Lstat(path) + if err1 == nil && dir.IsDir() { + return nil + } + return err + } + return nil +} From 997d673b8327d56e2385b2cb69fc0ad9b8d496a7 Mon Sep 17 00:00:00 2001 From: luoliwoshang <2643523683@qq.com> Date: Wed, 14 Aug 2024 10:14:30 +0800 Subject: [PATCH 2/2] lib/os:MkdirAll use 1.21.13 --- internal/lib/internal/filepathlite/path.go | 53 ------------------- .../lib/internal/filepathlite/path_unix.go | 30 ----------- internal/lib/internal/stringslite/strings.go | 17 ------ internal/lib/os/path.go | 26 ++++----- 4 files changed, 9 insertions(+), 117 deletions(-) delete mode 100644 internal/lib/internal/filepathlite/path.go delete mode 100644 internal/lib/internal/filepathlite/path_unix.go delete mode 100644 internal/lib/internal/stringslite/strings.go diff --git a/internal/lib/internal/filepathlite/path.go b/internal/lib/internal/filepathlite/path.go deleted file mode 100644 index 2aaed5337..000000000 --- a/internal/lib/internal/filepathlite/path.go +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package filepathlite - -import ( - "github.com/goplus/llgo/internal/lib/internal/stringslite" -) - -// FromSlash is filepath.ToSlash. -func FromSlash(path string) string { - if Separator == '/' { - return path - } - return replaceStringByte(path, '/', Separator) -} - -func replaceStringByte(s string, old, new byte) string { - if stringslite.IndexByte(s, old) == -1 { - return s - } - n := []byte(s) - for i := range n { - if n[i] == old { - n[i] = new - } - } - return string(n) -} - -// VolumeName is filepath.VolumeName. -func VolumeName(path string) string { - return FromSlash(path[:volumeNameLen(path)]) -} - -// VolumeNameLen returns the length of the leading volume name on Windows. -// It returns 0 elsewhere. -func VolumeNameLen(path string) int { - return volumeNameLen(path) -} diff --git a/internal/lib/internal/filepathlite/path_unix.go b/internal/lib/internal/filepathlite/path_unix.go deleted file mode 100644 index e2f25598b..000000000 --- a/internal/lib/internal/filepathlite/path_unix.go +++ /dev/null @@ -1,30 +0,0 @@ -//go:build unix || (js && wasm) || wasip1 - -/* - * Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package filepathlite - -const ( - Separator = '/' // OS-specific path separator - ListSeparator = ':' // OS-specific path list separator -) - -// volumeNameLen returns length of the leading volume name on Windows. -// It returns 0 elsewhere. -func volumeNameLen(path string) int { - return 0 -} diff --git a/internal/lib/internal/stringslite/strings.go b/internal/lib/internal/stringslite/strings.go deleted file mode 100644 index 4ad916cc9..000000000 --- a/internal/lib/internal/stringslite/strings.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2024 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package stringslite implements a subset of strings, -// only using packages that may be imported by "os". -// -// Tests for these functions are in the strings package. -package stringslite - -import ( - "github.com/goplus/llgo/internal/lib/internal/bytealg" -) - -func IndexByte(s string, c byte) int { - return bytealg.IndexByteString(s, c) -} diff --git a/internal/lib/os/path.go b/internal/lib/os/path.go index a0bbb7208..aee2266c7 100644 --- a/internal/lib/os/path.go +++ b/internal/lib/os/path.go @@ -2,8 +2,6 @@ package os import ( "syscall" - - "github.com/goplus/llgo/internal/lib/internal/filepathlite" ) // MkdirAll creates a directory named path, @@ -24,25 +22,19 @@ func MkdirAll(path string, perm FileMode) error { } // Slow path: make sure parent exists and then call Mkdir for path. - - // Extract the parent folder from path by first removing any trailing - // path separator and then scanning backward until finding a path - // separator or reaching the beginning of the string. - i := len(path) - 1 - for i >= 0 && IsPathSeparator(path[i]) { + i := len(path) + for i > 0 && IsPathSeparator(path[i-1]) { // Skip trailing path separator. i-- } - for i >= 0 && !IsPathSeparator(path[i]) { - i-- - } - if i < 0 { - i = 0 + + j := i + for j > 0 && !IsPathSeparator(path[j-1]) { // Scan backward over element. + j-- } - // If there is a parent directory, and it is not the volume name, - // recurse to ensure parent directory exists. - if parent := path[:i]; len(parent) > len(filepathlite.VolumeName(path)) { - err = MkdirAll(parent, perm) + if j > 1 { + // Create parent. + err = MkdirAll(fixRootDirectory(path[:j-1]), perm) if err != nil { return err }