diff --git a/vlib/os/os.v b/vlib/os/os.v index eaf09668e6..9f8b939aad 100644 --- a/vlib/os/os.v +++ b/vlib/os/os.v @@ -511,23 +511,6 @@ pub fn is_executable(path string) bool { return C.access(charptr(path.str), x_ok) != -1 } -// `is_writable_folder` - `folder` exists and is writable to the process -pub fn is_writable_folder(folder string) ?bool { - if !os.exists(folder) { - return error('`$folder` does not exist') - } - if !os.is_dir(folder) { - return error('`folder` is not a folder') - } - tmp_perm_check := os.join_path(folder, 'tmp_perm_check') - mut f := os.open_file(tmp_perm_check, 'w+', 0o700) or { - return error('cannot write to folder `$folder`: $err') - } - f.close() - os.rm(tmp_perm_check) - return true -} - // `is_writable` returns `true` if `path` is writable. pub fn is_writable(path string) bool { $if windows { @@ -638,7 +621,7 @@ pub fn dir(path string) string { pub fn base_dir(path string) string { posx := path.last_index(path_separator) or { - return path + return path.clone() } // NB: *without* terminating / return path[..posx] diff --git a/vlib/os/os_nix.c.v b/vlib/os/os_nix.c.v index a59d23fab4..1d3635abe1 100644 --- a/vlib/os/os_nix.c.v +++ b/vlib/os/os_nix.c.v @@ -190,3 +190,24 @@ pub fn (mut f File) close() { pub fn debugger_present() bool { return false } + +fn C.mkstemp(stemplate byteptr) int +// `is_writable_folder` - `folder` exists and is writable to the process +pub fn is_writable_folder(folder string) ?bool { + if !os.exists(folder) { + return error('`$folder` does not exist') + } + if !os.is_dir(folder) { + return error('`folder` is not a folder') + } + tmp_perm_check := os.join_path(folder, 'XXXXXX') + unsafe { + x := C.mkstemp(tmp_perm_check.str) + if -1 == x { + return error('folder `$folder` is not writable') + } + C.close(x) + } + os.rm(tmp_perm_check) + return true +} diff --git a/vlib/os/os_windows.c.v b/vlib/os/os_windows.c.v index d80bf0f7d0..e108952661 100644 --- a/vlib/os/os_windows.c.v +++ b/vlib/os/os_windows.c.v @@ -366,3 +366,21 @@ pub fn uname() Uname { machine: unknown } } + + +// `is_writable_folder` - `folder` exists and is writable to the process +pub fn is_writable_folder(folder string) ?bool { + if !os.exists(folder) { + return error('`$folder` does not exist') + } + if !os.is_dir(folder) { + return error('`folder` is not a folder') + } + tmp_perm_check := os.join_path(folder, 'tmp_perm_check') + mut f := os.open_file(tmp_perm_check, 'w+', 0o700) or { + return error('cannot write to folder $folder: $err') + } + f.close() + os.rm(tmp_perm_check) + return true +} diff --git a/vlib/v/builder/compile.v b/vlib/v/builder/compile.v index ac63f449c7..cdb2c93662 100644 --- a/vlib/v/builder/compile.v +++ b/vlib/v/builder/compile.v @@ -27,6 +27,18 @@ fn get_vtmp_filename(base_file_name, postfix string) string { } pub fn compile(command string, pref &pref.Preferences) { + odir := os.base_dir(pref.out_name) + // When pref.out_name is just the name of an executable, i.e. `./v -o executable main.v` + // without a folder component, just use the current folder instead: + mut output_folder := odir + if odir.len == pref.out_name.len { + output_folder = os.getwd() + } + os.is_writable_folder(output_folder) or { + // An early error here, is better than an unclear C error later: + verror(err) + exit(1) + } // Construct the V object from command line arguments mut b := new_builder(pref) if pref.is_verbose {