REBOL [
Title: "Sandbox Port"
Author: "Christopher Ross-Gill"
Date: 9-Jan-2007
]
config: construct [
file-domains: [
; use a string-directory pair to set file domains
"sbox" %/path/to/sandbox/
]
]
;--## EXTENDED CORE FUNCTIONS
;-------------------------------------------------------------------##
context [
set 'with func [object [object! port!] block [block!]][
do bind block in object 'self
]
]
;--## PORT HELPERS
;-------------------------------------------------------------------##
context [
set 'add-protocol func ['proto-name proto-port-id proto-handler][
unless in system/schemes proto-name [
system/schemes: make system/schemes compose [
(to-set-word proto-name) #[none]
]
]
set in system/schemes proto-name make system/standard/port [
scheme: proto-name
port-id: proto-port-id
handler: proto-handler
passive: none
cache-size: 5
proxy: make object! [host: port-id: user: pass: type: bypass: #[none]]
]
]
codes: [read 1 write 2 append 4 new 8 binary 32 lines 64]
set 'get-port-flags func [port words][
remove-each word copy words [
word: select codes word
word <> (port/state/flags and word)
]
]
]
;--## SANDBOX FILESYSTEM
;-------------------------------------------------------------------##
context [
chars: charset [#"a" - #"z" #"0" - #"9" "-_!+%"]
parse-uri: func [uri /local domain root path target][
if all [
parse/all uri [
"files://"
copy domain some chars #"/"
copy path any [some chars #"/"]
copy target opt [any chars #"." 1 10 chars]
]
root: select config/file-domains domain
][
reduce [
root
domain
all [path to-file path]
all [target to-file target]
]
]
]
rights: [
folder [
owner-read: group-read: world-read:
owner-write: group-write: world-write:
owner-execute: group-execute: world-execute: #[true]
]
file [
owner-read: group-read: world-read:
owner-write: group-write: world-write: #[true]
owner-execute: group-execute: world-execute: #[false]
]
]
set-rights: func [file access][
unless find [1 3] system/version/4 [
set-modes file rights/:access
]
]
break-path: func [[catch] target [file!] base [file!] /local path mk][
path: make block! []
either parse/all target: form target [
base some [
thru #"/" mk: (append path to-file copy/part target mk)
] end
][return path][
throw make error! reduce ['access 'invalid-path target]
]
]
make-dir: func [[catch] path [file!] /root base [file!] /sub /local dirs][
all [empty? path return path]
if exists? path [
return either dir? path [path][false]
]
either sub [
close throw-on-error [open/new path]
any [
system/words/find [1 3] system/version/4
throw-on-error [set-rights path 'folder]
]
][
dirs: break-path path base
foreach path dirs [make-dir/sub path]
]
path
]
get-subfolders: func [folder /deep /local tree files][
tree: []
any [deep clear tree]
insert tree folder: dirize folder
files: read folder
foreach file files [
if dir? folder/:file [get-subfolders/deep folder/:file]
]
tree
]
system/words/delete: func [[catch] target [url!] /pare /local path folder err][
either error? set/any 'err try [
; Delete Children
if dir? target [
folder: get-subfolders target
foreach path folder [close clear open path]
]
; Delete Target
set [path target] split-path target
folder: open path
remove find folder target
close folder
; Delete Empty Parents
if pare [
while [
pare: empty? folder: open path
close folder
pare
][
set [path target] split-path path
folder: open path
remove find folder target
close folder
]
]
][throw err][path]
]
; INTERFACE
actions: context [
port-flags: system/standard/port-flags/pass-thru
init: func [[catch] port url /local spec][
unless all [
url? url
spec: parse-uri url
][
make error! reform ["Spec Error:" url]
]
with port [
set [host path target] next spec
locals: context [
flags: []
root: first spec
folder: join root any [path ""]
file: join folder any [target ""]
suffix: suffix? file
open: #[none]
]
sub-port: make port! locals/file
]
]
open: func [port][
with port [
locals/flags: get-port-flags port [read write append new binary lines]
all [
system/words/find locals/flags 'new
not dir? locals/folder
make-dir/root locals/folder locals/root
]
either all [
any [
exists? locals/file
system/words/find locals/flags 'new
]
system/words/open/mode sub-port locals/flags
][
locals/open: true
state/tail: sub-port/state/tail
][
state/tail: 0
]
state/index: 0
state/flags: state/flags or port-flags
]
]
copy: func [port][
with port [
any [locals/open return #[none]]
user-data: system/words/copy skip sub-port state/index
all [
block? user-data block? state/custom
remove-each file user-data [not parse file state/custom]
]
user-data
]
]
insert: func [[catch] port data][
with port [
any [locals/open exit]
throw-on-error [
system/words/insert sub-port data
set-rights sub-port 'file
]
]
port
]
remove: func [port][
with port [
any [locals/open exit]
sub-port: skip sub-port state/index
system/words/remove/part sub-port state/num
]
port
]
find: func [port value][
any [port/locals/open return #[none]]
if value: system/words/find port/sub-port value [
port/sub-port: :value
port
]
]
close: func [port][
with port [
any [locals/open exit]
system/words/close sub-port
]
port
]
query: func [port][
with port [
system/words/query sub-port
size: sub-port/size
date: sub-port/date
status: sub-port/status
]
]
]
add-protocol files 0 actions
]