os: add is_executable, is_writable and is_readable
							parent
							
								
									126289c19b
								
							
						
					
					
						commit
						025efcb731
					
				
							
								
								
									
										47
									
								
								vlib/os/os.v
								
								
								
								
							
							
						
						
									
										47
									
								
								vlib/os/os.v
								
								
								
								
							| 
						 | 
					@ -505,16 +505,59 @@ pub fn unsetenv(name string) int {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						F_OK = 0
 | 
				
			||||||
 | 
						X_OK = 1
 | 
				
			||||||
 | 
						W_OK = 2
 | 
				
			||||||
 | 
						R_OK = 4
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// exists returns true if `path` exists.
 | 
					// exists returns true if `path` exists.
 | 
				
			||||||
pub fn exists(path string) bool {
 | 
					pub fn exists(path string) bool {
 | 
				
			||||||
	$if windows {
 | 
						$if windows {
 | 
				
			||||||
		p := path.replace('/', '\\')
 | 
							p := path.replace('/', '\\')
 | 
				
			||||||
		return C._waccess(p.to_wide(), 0) != -1
 | 
							return C._waccess(p.to_wide(), F_OK) != -1
 | 
				
			||||||
	} $else {
 | 
						} $else {
 | 
				
			||||||
		return C.access(path.str, 0) != -1
 | 
							return C.access(path.str, F_OK) != -1
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// `is_executable` returns `true` if `path` is executable.
 | 
				
			||||||
 | 
					pub fn is_executable(path string) bool {
 | 
				
			||||||
 | 
					  $if windows {
 | 
				
			||||||
 | 
					    // NB: https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/access-waccess?view=vs-2019
 | 
				
			||||||
 | 
					    // i.e. there is no X bit there, the modes can be:
 | 
				
			||||||
 | 
					    // 00 Existence only
 | 
				
			||||||
 | 
					    // 02 Write-only
 | 
				
			||||||
 | 
					    // 04 Read-only
 | 
				
			||||||
 | 
					    // 06 Read and write
 | 
				
			||||||
 | 
					    p := os.realpath( path )
 | 
				
			||||||
 | 
					    return ( os.exists( p ) && p.ends_with('.exe') )
 | 
				
			||||||
 | 
					  } $else {
 | 
				
			||||||
 | 
					    return C.access(path.str, X_OK) != -1
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// `is_writable` returns `true` if `path` is writable.
 | 
				
			||||||
 | 
					pub fn is_writable(path string) bool {
 | 
				
			||||||
 | 
					  $if windows {
 | 
				
			||||||
 | 
					    p := path.replace('/', '\\')
 | 
				
			||||||
 | 
					    return C._waccess(p.to_wide(), W_OK) != -1
 | 
				
			||||||
 | 
					  } $else {
 | 
				
			||||||
 | 
					    return C.access(path.str, W_OK) != -1
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// `is_readable` returns `true` if `path` is readable.
 | 
				
			||||||
 | 
					pub fn is_readable(path string) bool {
 | 
				
			||||||
 | 
					  $if windows {
 | 
				
			||||||
 | 
					    p := path.replace('/', '\\')
 | 
				
			||||||
 | 
					    return C._waccess(p.to_wide(), R_OK) != -1
 | 
				
			||||||
 | 
					  } $else {
 | 
				
			||||||
 | 
					    return C.access(path.str, R_OK) != -1
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[deprecated]
 | 
					[deprecated]
 | 
				
			||||||
pub fn file_exists(_path string) bool {
 | 
					pub fn file_exists(_path string) bool {
 | 
				
			||||||
	panic('use os.exists(path) instead of os.file_exists(path)')
 | 
						panic('use os.exists(path) instead of os.file_exists(path)')
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -107,7 +107,7 @@ fn test_walk() {
 | 
				
			||||||
    os.write_file(file1,'test-1')
 | 
					    os.write_file(file1,'test-1')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    os.walk(folder, walk_callback)
 | 
					    os.walk(folder, walk_callback)
 | 
				
			||||||
	
 | 
					
 | 
				
			||||||
	os.rm(file1)
 | 
						os.rm(file1)
 | 
				
			||||||
	os.rmdir(folder)
 | 
						os.rmdir(folder)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -150,17 +150,17 @@ fn test_tmpdir(){
 | 
				
			||||||
	t := os.tmpdir()
 | 
						t := os.tmpdir()
 | 
				
			||||||
	assert t.len > 0
 | 
						assert t.len > 0
 | 
				
			||||||
	assert os.is_dir(t)
 | 
						assert os.is_dir(t)
 | 
				
			||||||
	
 | 
					
 | 
				
			||||||
	tfile := t + os.path_separator + 'tmpfile.txt'
 | 
						tfile := t + os.path_separator + 'tmpfile.txt'
 | 
				
			||||||
	
 | 
					
 | 
				
			||||||
	os.rm(tfile) // just in case
 | 
						os.rm(tfile) // just in case
 | 
				
			||||||
	
 | 
					
 | 
				
			||||||
	tfile_content := 'this is a temporary file'
 | 
						tfile_content := 'this is a temporary file'
 | 
				
			||||||
	os.write_file(tfile, tfile_content)
 | 
						os.write_file(tfile, tfile_content)
 | 
				
			||||||
	
 | 
					
 | 
				
			||||||
	tfile_content_read := os.read_file(tfile) or { panic(err) }
 | 
						tfile_content_read := os.read_file(tfile) or { panic(err) }
 | 
				
			||||||
	assert tfile_content_read == tfile_content
 | 
						assert tfile_content_read == tfile_content
 | 
				
			||||||
	
 | 
					
 | 
				
			||||||
	os.rm(tfile)
 | 
						os.rm(tfile)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -175,7 +175,7 @@ fn test_make_symlink_check_is_link_and_remove_symlink() {
 | 
				
			||||||
   folder  := 'tfolder'
 | 
					   folder  := 'tfolder'
 | 
				
			||||||
   symlink := 'tsymlink'
 | 
					   symlink := 'tsymlink'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   os.rm(symlink) 
 | 
					   os.rm(symlink)
 | 
				
			||||||
   os.rm(folder)
 | 
					   os.rm(folder)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   os.mkdir(folder) or { panic(err) }
 | 
					   os.mkdir(folder) or { panic(err) }
 | 
				
			||||||
| 
						 | 
					@ -185,12 +185,12 @@ fn test_make_symlink_check_is_link_and_remove_symlink() {
 | 
				
			||||||
   os.system('ln -s $folder $symlink')
 | 
					   os.system('ln -s $folder $symlink')
 | 
				
			||||||
   assert os.is_link(symlink) == true
 | 
					   assert os.is_link(symlink) == true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   os.rm(symlink) 
 | 
					   os.rm(symlink)
 | 
				
			||||||
   os.rm(folder)
 | 
					   os.rm(folder)
 | 
				
			||||||
   
 | 
					
 | 
				
			||||||
   folder_exists := os.is_dir(folder)
 | 
					   folder_exists := os.is_dir(folder)
 | 
				
			||||||
   assert folder_exists == false
 | 
					   assert folder_exists == false
 | 
				
			||||||
   
 | 
					
 | 
				
			||||||
   symlink_exists := os.is_link(symlink)
 | 
					   symlink_exists := os.is_link(symlink)
 | 
				
			||||||
   assert symlink_exists == false
 | 
					   assert symlink_exists == false
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -234,6 +234,32 @@ fn test_symlink() {
 | 
				
			||||||
  os.rm('symlink2')
 | 
					  os.rm('symlink2')
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn test_is_executable_writable_readable() {
 | 
				
			||||||
 | 
					  file_name := os.tmpdir() + os.path_separator + 'rwxfile.exe'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  mut f := os.create(file_name) or {
 | 
				
			||||||
 | 
					    eprintln('failed to create file $file_name')
 | 
				
			||||||
 | 
					    return
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  f.close()
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  $if !windows {
 | 
				
			||||||
 | 
					    os.chmod(file_name, 0600) // mark as readable && writable, but NOT executable  
 | 
				
			||||||
 | 
					    assert os.is_writable(file_name)
 | 
				
			||||||
 | 
					    assert os.is_readable(file_name)
 | 
				
			||||||
 | 
					    assert !os.is_executable(file_name)  
 | 
				
			||||||
 | 
					    os.chmod(file_name, 0700) // mark as executable too
 | 
				
			||||||
 | 
					    assert os.is_executable(file_name)
 | 
				
			||||||
 | 
					  } $else {
 | 
				
			||||||
 | 
					    assert os.is_writable(file_name)
 | 
				
			||||||
 | 
					    assert os.is_readable(file_name)
 | 
				
			||||||
 | 
					    assert os.is_executable(file_name)    
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // We finally delete the test file.
 | 
				
			||||||
 | 
					  os.rm(file_name)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// this function is called by both test_aaa_setup & test_zzz_cleanup
 | 
					// this function is called by both test_aaa_setup & test_zzz_cleanup
 | 
				
			||||||
// it ensures that os tests do not polute the filesystem with leftover
 | 
					// it ensures that os tests do not polute the filesystem with leftover
 | 
				
			||||||
// files so that they can be run several times in a row.
 | 
					// files so that they can be run several times in a row.
 | 
				
			||||||
| 
						 | 
					@ -241,7 +267,7 @@ fn cleanup_leftovers(){
 | 
				
			||||||
	// possible leftovers from test_cp
 | 
						// possible leftovers from test_cp
 | 
				
			||||||
	os.rm('cp_example.txt')
 | 
						os.rm('cp_example.txt')
 | 
				
			||||||
	os.rm('cp_new_example.txt')
 | 
						os.rm('cp_new_example.txt')
 | 
				
			||||||
	
 | 
					
 | 
				
			||||||
	// possible leftovers from test_cp_r
 | 
						// possible leftovers from test_cp_r
 | 
				
			||||||
	os.rm('ex/ex2/ex2.txt')
 | 
						os.rm('ex/ex2/ex2.txt')
 | 
				
			||||||
	os.rmdir('ex/ex2')
 | 
						os.rmdir('ex/ex2')
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue