(* $Id: index.ml,v 1.1 2003-03-09 17:37:29 stolpmann Exp $
* ----------------------------------------------------------------------
*
*)
open Wd_types
open Wd_dialog
open Wd_run_cgi
(* IMPORTANT NOTE:
*
* The underlying NDBM implementation is required to allow arbitrary
* long key/value pairs. This is known to be true for GDBM and
* Berkeley DB, but it does not hold for the original Unix implementation.
* Single Unix Spec only demands that NDBM supports at least 1023 bytes
* for key plus value.
*
* The following code does not implement locking for the NDBM accesses.
* This should be added.
*)
let transaction f =
let dbm = Dbm.opendbm "./sessions" [ Dbm.Dbm_create; Dbm.Dbm_rdwr ] 0o666 in
let r = f dbm in
Dbm.close dbm;
r
;;
class dbm_session_manager : session_manager_type =
(* A new session manager that stored sessions into NDBM files. It is derived
* from database_session_manager by implementing the database access
* functions "allocate", "insert", "update", and "lookup".
*)
database_session_manager
~allocate:(fun () ->
transaction
(fun dbm ->
let next_key =
try int_of_string(Dbm.find dbm "nextid")
with Not_found -> 0
in
Dbm.replace dbm "nextid" (string_of_int (next_key+1));
next_key
))
~insert:(fun id skey ->
transaction
(fun dbm ->
let key = string_of_int id ^ ":" ^ skey in
Dbm.replace dbm (key ^ "-val") "";
Dbm.replace dbm (key ^ "-chk") "";
))
~update:(fun id skey value checksum ->
transaction
(fun dbm ->
let key = string_of_int id ^ ":" ^ skey in
try
let _ = Dbm.find dbm (key ^ "-val") in
Dbm.replace dbm (key ^ "-val") value;
Dbm.replace dbm (key ^ "-chk") checksum;
with
Not_found ->
raise Session_not_found))
~lookup:(fun id skey ->
transaction
(fun dbm ->
let key = string_of_int id ^ ":" ^ skey in
try
let value = Dbm.find dbm (key ^ "-val") in
let checksum = Dbm.find dbm (key ^ "-chk") in
(value,checksum)
with
Not_found ->
raise Session_not_found))
()
;;
let read_directory path =
(* Return the file names of the directory "path" as string list *)
let d = Unix.opendir path in
let rec readrec () =
try
let name = Unix.readdir d in
name :: readrec()
with
End_of_file -> []
in
let names = readrec() in
Unix.closedir d;
names
;;
let permissions kind perm =
(* Compute a textual representation of file 'kind' and
* permission mode 'perm'
*)
let first_letter =
match kind with
Unix.S_REG -> "-"
| Unix.S_DIR -> "d"
| Unix.S_CHR -> "c"
| Unix.S_BLK -> "b"
| Unix.S_LNK -> "l"
| Unix.S_FIFO -> "p"
| Unix.S_SOCK -> "s"
in
let s = ref "" in
let p = ref perm in
List.iter
(fun letter ->
begin
if !p mod 2 = 1 then
s := letter ^ !s
else
s := "-" ^ !s
end;
p := !p / 2)
[ "x"; "w"; "r"; "x"; "w"; "r"; "x"; "w"; "r" ];
s := first_letter ^ !s;
if (perm land 0o1000) > 0 then begin
if !s.[9] = 'x' then
!s.[9] <- 't'
else
!s.[9] <- 'T'
end;
if (perm land 0o2000) > 0 then begin
if !s.[6] = 'x' then
!s.[6] <- 's'
else
!s.[6] <- 'l'
end;
if (perm land 0o4000) > 0 then begin
if !s.[6] = 'x' then
!s.[6] <- 's'
else
!s.[6] <- 'S'
end;
!s
;;
let owner uid =
(* Converts the numerical uid to a string *)
try
(Unix.getpwuid uid).Unix.pw_name
with
Not_found -> string_of_int uid
;;
let group gid =
(* Converts the numerical gid to a string *)
try
(Unix.getgrgid gid).Unix.gr_name
with
Not_found -> string_of_int gid
;;
let timestring t =
(* Converts the time value t to a string *)
let tm = Unix.localtime t in
Printf.sprintf
"%04d-%02d-%02d %02d:%02d:%02d"
(tm.Unix.tm_year + 1900) (* Y2k-compliant *)
(tm.Unix.tm_mon + 1)
(tm.Unix.tm_mday)
(tm.Unix.tm_hour)
(tm.Unix.tm_min)
(tm.Unix.tm_sec)
;;
class directory universe name env =
object (self)
inherit Wd_dialog.dialog universe name env
method prepare_page() =
(* Compute the variable "listing": *)
match self # page_name with
"show-listing" ->
self # prepare_show_listing()
| _ ->
()
method private prepare_show_listing() =
let path = self # string_variable "path" in
let names = Sort.list
(fun a b -> a <= b)
(read_directory path) in (* file names *)
(* Get all necessary templates: *)
let t_directory_row = self # t_get "directory-row" in
let t_filename = self # t_get "filename" in
let t_filename_d = self # t_get "filename_d" in
let t0 = Unix.gettimeofday() in
(* Map 'names' to a tree list: *)
let rows =
List.map
(fun name ->
let path_name = Filename.concat path name in
let s = Unix.stat path_name in
let ls = Unix.lstat path_name in
(* If the file is a directory, use t_filename_d instead of
* t_filename:
*)
let t_fname =
match s.Unix.st_kind with
Unix.S_DIR -> t_filename_d
| _ -> t_filename
in
self # t_apply
t_directory_row
[ "filename", self # t_apply
t_fname
[ "value", self # t_text name ];
"fileperms", self # t_text (permissions
s.Unix.st_kind
s.Unix.st_perm);
"fileowner", self # t_text (owner s.Unix.st_uid);
"filegroup", self # t_text (group s.Unix.st_gid);
"filesize", self # t_text (string_of_int s.Unix.st_size);
"filemtime", self # t_text (timestring s.Unix.st_mtime);
"filesymlink",
match ls.Unix.st_kind with
Unix.S_LNK ->
self # t_apply_byname "symlink"
[ "value",
self # t_text (Unix.readlink path_name) ]
| _ -> self # t_empty;
]
)
names
in
let t1 = Unix.gettimeofday() in
(* Concatenate 'rows' and put result into 'listing': *)
self # put_tree "listing" (self # t_concat self#t_empty rows)
method private change_directory dirname =
(* Append [dirname] to the current directory path *)
match dirname with
"." -> ()
| ".." ->
let p = Filename.dirname
(self # string_variable "path") in
self # set_variable "path" (String_value p)
| _ ->
self # set_variable "path"
(String_value
(Filename.concat
(self # string_variable "path")
dirname))
method handle() =
match self # event with
Indexed_button ("goto_dir", dirname) ->
self # change_directory dirname
| Button "confirm" ->
self # change_directory (self # string_variable "next_path")
| Indexed_button("set_language", lang) ->
self # set_variable "lang" (String_value lang)
| Popup_request path ->
(* Executed just before the confirmation_popup appears: *)
self # set_variable "next_path" (String_value path)
| _ -> ()
end
;;
run
~session_manager:(new dbm_session_manager)
~reg:(fun universe ->
universe # register "directory" (new directory)
)
()
;;
(* ======================================================================
* History:
*
* $Log: index.ml,v $
* Revision 1.1 2003-03-09 17:37:29 stolpmann
* Initial revision.
*
*)