Plasma GitLab Archive
Projects Blog Knowledge

(* $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.
 *
 *)

This web site is published by Informatikbüro Gerd Stolpmann
Powered by Caml