Index: /trunk/Makefile.in
===================================================================
--- /trunk/Makefile.in	(revision 166)
+++ /trunk/Makefile.in	(revision 167)
@@ -117,5 +117,5 @@
 	rijndael-boxes-fst.h sh_socket.h sh_ignore.h sh_prelude.h \
 	sh_mounts.h sh_userfiles.h sh_static.h sh_prelink.h \
-	sh_processcheck.h sh_portcheck.h sh_pthread.h
+	sh_processcheck.h sh_portcheck.h sh_pthread.h sh_string.h
 
 
@@ -151,5 +151,5 @@
 	$(srcsrc)/sh_portcheck.c \
 	$(srcsrc)/sh_processcheck.c $(srcsrc)/sh_prelude_old.c \
-	$(srcsrc)/sh_pthread.c
+	$(srcsrc)/sh_pthread.c $(srcsrc)/sh_string.c
 
 OBJECTS = sh_files.o sh_tiger0.o sh_tiger2.o sh_tiger2_64.o \
@@ -165,5 +165,5 @@
 	sh_mounts.o sh_userfiles.o sh_prelink.o sh_static.o \
 	sh_processcheck.o sh_portcheck.o sh_prelude_old.o \
-	sh_pthread.o
+	sh_pthread.o sh_string.o
 
 KERN = kern_head.h kern_head.c
@@ -1642,5 +1642,5 @@
 sh_getopt.o: $(srcsrc)/sh_getopt.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_error.h $(srcinc)/sh_getopt.h $(srcinc)/sh_files.h $(srcinc)/sh_utils.h $(srcinc)/sh_mail.h $(srcinc)/sh_forward.h $(srcinc)/sh_hash.h $(srcinc)/sh_extern.h 
 sh_readconf.o: $(srcsrc)/sh_readconf.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_error.h $(srcinc)/sh_database.h $(srcinc)/sh_unix.h $(srcinc)/sh_utils.h $(srcinc)/sh_files.h $(srcinc)/sh_mail.h $(srcinc)/sh_calls.h $(srcinc)/sh_tiger.h $(srcinc)/sh_forward.h $(srcinc)/sh_modules.h $(srcinc)/sh_gpg.h $(srcinc)/sh_hash.h $(srcinc)/sh_ignore.h $(srcinc)/sh_prelink.h $(srcinc)/sh_extern.h $(srcinc)/sh_database.h $(srcinc)/sh_prelude.h 
-sh_tiger0.o: $(srcsrc)/sh_tiger0.c Makefile config_xor.h $(srcinc)/sh_tiger.h $(srcinc)/sh_unix.h $(srcinc)/sh_error.h $(srcinc)/sh_utils.h $(srcinc)/sh_pthread.h 
+sh_tiger0.o: $(srcsrc)/sh_tiger0.c Makefile config_xor.h $(srcinc)/sh_tiger.h $(srcinc)/sh_unix.h $(srcinc)/sh_error.h $(srcinc)/sh_utils.h $(srcinc)/sh_pthread.h $(srcinc)/sh_string.h 
 sh_tiger1.o: $(srcsrc)/sh_tiger1.c Makefile config_xor.h 
 sh_tiger2.o: $(srcsrc)/sh_tiger2.c Makefile config_xor.h 
@@ -1680,5 +1680,5 @@
 exepack_mkdata.o: $(srcsrc)/exepack_mkdata.c Makefile config.h $(srcinc)/minilzo.h 
 minilzo.o: $(srcsrc)/minilzo.c Makefile $(srcinc)/minilzo.h 
-slib.o: $(srcsrc)/slib.c Makefile config_xor.h $(srcinc)/slib.h $(srcinc)/sh_calls.h $(srcinc)/sh_static.h $(srcinc)/sh_pthread.h $(srcinc)/sh_mem.h 
+slib.o: $(srcsrc)/slib.c Makefile config_xor.h $(srcinc)/slib.h $(srcinc)/sh_calls.h $(srcinc)/sh_static.h $(srcinc)/sh_pthread.h $(srcinc)/sh_string.h $(srcinc)/sh_mem.h 
 rijndael-alg-fst.o: $(srcsrc)/rijndael-alg-fst.c Makefile config_xor.h $(srcinc)/rijndael-alg-fst.h $(srcinc)/rijndael-boxes-fst.h 
 rijndael-api-fst.o: $(srcsrc)/rijndael-api-fst.c Makefile config_xor.h $(srcinc)/rijndael-alg-fst.h $(srcinc)/rijndael-api-fst.h 
@@ -1698,2 +1698,3 @@
 sh_portcheck.o: $(srcsrc)/sh_portcheck.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_error.h $(srcinc)/sh_mem.h $(srcinc)/sh_calls.h $(srcinc)/sh_utils.h $(srcinc)/sh_modules.h $(srcinc)/sh_static.h $(srcinc)/sh_pthread.h $(srcinc)/CuTest.h 
 sh_pthread.o: $(srcsrc)/sh_pthread.c Makefile config_xor.h $(srcinc)/sh_pthread.h $(srcinc)/sh_calls.h $(srcinc)/sh_modules.h 
+sh_string.o: $(srcsrc)/sh_string.c Makefile $(srcinc)/sh_string.h $(srcinc)/sh_mem.h 
Index: /trunk/depend.dep
===================================================================
--- /trunk/depend.dep	(revision 166)
+++ /trunk/depend.dep	(revision 167)
@@ -8,5 +8,5 @@
 sh_getopt.o: $(srcsrc)/sh_getopt.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_error.h $(srcinc)/sh_getopt.h $(srcinc)/sh_files.h $(srcinc)/sh_utils.h $(srcinc)/sh_mail.h $(srcinc)/sh_forward.h $(srcinc)/sh_hash.h $(srcinc)/sh_extern.h 
 sh_readconf.o: $(srcsrc)/sh_readconf.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_error.h $(srcinc)/sh_database.h $(srcinc)/sh_unix.h $(srcinc)/sh_utils.h $(srcinc)/sh_files.h $(srcinc)/sh_mail.h $(srcinc)/sh_calls.h $(srcinc)/sh_tiger.h $(srcinc)/sh_forward.h $(srcinc)/sh_modules.h $(srcinc)/sh_gpg.h $(srcinc)/sh_hash.h $(srcinc)/sh_ignore.h $(srcinc)/sh_prelink.h $(srcinc)/sh_extern.h $(srcinc)/sh_database.h $(srcinc)/sh_prelude.h 
-sh_tiger0.o: $(srcsrc)/sh_tiger0.c Makefile config_xor.h $(srcinc)/sh_tiger.h $(srcinc)/sh_unix.h $(srcinc)/sh_error.h $(srcinc)/sh_utils.h $(srcinc)/sh_pthread.h 
+sh_tiger0.o: $(srcsrc)/sh_tiger0.c Makefile config_xor.h $(srcinc)/sh_tiger.h $(srcinc)/sh_unix.h $(srcinc)/sh_error.h $(srcinc)/sh_utils.h $(srcinc)/sh_pthread.h $(srcinc)/sh_string.h 
 sh_tiger1.o: $(srcsrc)/sh_tiger1.c Makefile config_xor.h 
 sh_tiger2.o: $(srcsrc)/sh_tiger2.c Makefile config_xor.h 
@@ -46,5 +46,5 @@
 exepack_mkdata.o: $(srcsrc)/exepack_mkdata.c Makefile config.h $(srcinc)/minilzo.h 
 minilzo.o: $(srcsrc)/minilzo.c Makefile $(srcinc)/minilzo.h 
-slib.o: $(srcsrc)/slib.c Makefile config_xor.h $(srcinc)/slib.h $(srcinc)/sh_calls.h $(srcinc)/sh_static.h $(srcinc)/sh_pthread.h $(srcinc)/sh_mem.h 
+slib.o: $(srcsrc)/slib.c Makefile config_xor.h $(srcinc)/slib.h $(srcinc)/sh_calls.h $(srcinc)/sh_static.h $(srcinc)/sh_pthread.h $(srcinc)/sh_string.h $(srcinc)/sh_mem.h 
 rijndael-alg-fst.o: $(srcsrc)/rijndael-alg-fst.c Makefile config_xor.h $(srcinc)/rijndael-alg-fst.h $(srcinc)/rijndael-boxes-fst.h 
 rijndael-api-fst.o: $(srcsrc)/rijndael-api-fst.c Makefile config_xor.h $(srcinc)/rijndael-alg-fst.h $(srcinc)/rijndael-api-fst.h 
@@ -63,2 +63,3 @@
 sh_pthread.o: $(srcsrc)/sh_pthread.c Makefile config_xor.h $(srcinc)/sh_pthread.h $(srcinc)/sh_calls.h $(srcinc)/sh_modules.h 
 kern_head.o: $(srcsrc)/kern_head.c Makefile config.h $(srcinc)/kern_head.h $(srcinc)/kern_head.h 
+sh_string.o: $(srcsrc)/sh_string.c Makefile $(srcinc)/sh_string.h $(srcinc)/sh_mem.h 
Index: /trunk/depend.sum
===================================================================
--- /trunk/depend.sum	(revision 166)
+++ /trunk/depend.sum	(revision 167)
@@ -1,1 +1,1 @@
-2613935365
+3237390887
Index: /trunk/docs/Changelog
===================================================================
--- /trunk/docs/Changelog	(revision 166)
+++ /trunk/docs/Changelog	(revision 167)
@@ -1,6 +1,12 @@
 2.4.4:
+	* fill content if MODI_TXT, base64 encode and add as link_path 
+	  in sh_unix.c; add to report in sh_hash.c; needs listing option
 	* testsuite: add test for gpg fingerprint option
 	* sh_extern.c: add 'CloseCommand' for syntactic sugar, 
 	  add in testsuite
+
+2.4.3a:
+	* fix compile error cause by open() with O_CREAT and no third argument
+	  (reported by J.-S. Eon)
 
 2.4.3:
Index: /trunk/include/sh_unix.h
===================================================================
--- /trunk/include/sh_unix.h	(revision 166)
+++ /trunk/include/sh_unix.h	(revision 167)
@@ -90,4 +90,8 @@
 /* use prelink     */
 #define MODI_PREL (1 << 13)
+/* get content     */
+#define MODI_TXT (1 << 14)
+
+#define SH_TXT_MAX 9200
 
 #define MASK_ALLIGNORE_  0
@@ -140,5 +144,5 @@
   time_t           ctime;
 
-  char             linkpath[PATH_MAX];
+  char           * link_path;
   mode_t           linkmode;
   char             link_c_mode[11];
Index: /trunk/include/sh_utils.h
===================================================================
--- /trunk/include/sh_utils.h	(revision 166)
+++ /trunk/include/sh_utils.h	(revision 167)
@@ -190,3 +190,24 @@
 char * sh_util_basename(const char * fullpath);
 
+/* required size (including terminating NULL) for string of strlen l
+ */
+#define SH_B64_SIZ(l)  (1 + ((((l) + 2) / 3) * 4))
+
+/* return len of encoded string
+ */
+size_t sh_util_base64_enc (unsigned char * out, const unsigned char * instr, 
+			   size_t lin);
+
+/* return allocated encoded string in out, return its len
+ */
+size_t sh_util_base64_enc_alloc (char **out, const char *in, size_t inlen);
+
+/* return len of decoded string
+ */  
+size_t sh_util_base64_dec (unsigned char *out, const unsigned char *in, size_t lin);
+
+/* return allocated decoded string in out, return its len
+ */  
+size_t sh_util_base64_dec_alloc (unsigned char **out, const unsigned char *in, size_t lin);
+
 #endif
Index: /trunk/include/slib.h
===================================================================
--- /trunk/include/slib.h	(revision 166)
+++ /trunk/include/slib.h	(revision 167)
@@ -23,4 +23,6 @@
 #include <unistd.h>
 #endif
+
+#include "sh_string.h"
 
 /****************
@@ -333,4 +335,12 @@
   SL_TICKET  sl_open_rdwr_trunc  (const char * fname, int priviledge_mode);
 
+  /* Initialize the content sh_string.
+   */
+  int sl_init_content (SL_TICKET ticket, size_t size);
+
+  /* Get the (pointer to) the content sh_string.
+   */
+  sh_string * sl_get_content (SL_TICKET ticket);
+
   /* Close file.
    */
Index: /trunk/src/cutest_sh_utils.c
===================================================================
--- /trunk/src/cutest_sh_utils.c	(revision 166)
+++ /trunk/src/cutest_sh_utils.c	(revision 167)
@@ -128,4 +128,53 @@
 }
 
+void Test_sh_util_base64_enc_ok (CuTest *tc) {
+  unsigned char   out[64];
+  unsigned char   ou2[64];
+  int    ret;
+  unsigned char   inp0[64] = "";
+  unsigned char   inp1[64] = "A";
+  unsigned char   inp2[64] = "AB";
+  unsigned char   inp3[64] = "ABC";
+  unsigned char   inp4[64] = "ABCD";
+
+  ret = sh_util_base64_enc (out, inp0, strlen((char*)inp0));
+  CuAssertIntEquals(tc, ret, 0);
+  CuAssertStrEquals(tc, "", (char*)out);
+  ret = sh_util_base64_dec (ou2, out, strlen((char*)out));
+  CuAssertIntEquals(tc, ret, 0);
+  CuAssertStrEquals(tc, (char*)inp0, (char*)ou2);
+
+  ret = sh_util_base64_enc (out, inp1, strlen((char*)inp1));
+  CuAssertIntEquals(tc, ret, 4);
+  CuAssertStrEquals(tc, "QQ??", (char*)out);
+  ret = sh_util_base64_dec (ou2, out, strlen((char*)out));
+  CuAssertStrEquals(tc, (char*)inp1, (char*)ou2);
+  CuAssertIntEquals(tc, 1, ret);
+
+  ret = sh_util_base64_enc (out, inp2, strlen((char*)inp2));
+  CuAssertIntEquals(tc, ret, 4);
+  CuAssertStrEquals(tc, "QUI?", (char*)out);
+  ret = sh_util_base64_dec (ou2, out, strlen((char*)out));
+  CuAssertStrEquals(tc, (char*)inp2, (char*)ou2);
+  CuAssertIntEquals(tc, 2, ret);
+
+  ret = sh_util_base64_enc (out, inp3, strlen((char*)inp3));
+  CuAssertIntEquals(tc, ret, 4);
+  CuAssertStrEquals(tc, "QUJD", (char*)out);
+  ret = sh_util_base64_dec (ou2, out, strlen((char*)out));
+  CuAssertStrEquals(tc, (char*)inp3, (char*)ou2);
+  CuAssertIntEquals(tc, 3, ret);
+
+  ret = sh_util_base64_enc (out, inp4, strlen((char*)inp4));
+  CuAssertIntEquals(tc, ret, 8);
+  CuAssertStrEquals(tc, "QUJDRA??", (char*)out);
+  ret = sh_util_base64_dec (ou2, out, strlen((char*)out));
+  CuAssertStrEquals(tc, (char*)inp4, (char*)ou2);
+  CuAssertIntEquals(tc, 4, ret);
+
+
+  return;
+}
+
 void Test_sh_util_dirname_ok (CuTest *tc) {
   char * ret = 0;
Index: /trunk/src/sh_files.c
===================================================================
--- /trunk/src/sh_files.c	(revision 166)
+++ /trunk/src/sh_files.c	(revision 167)
@@ -616,4 +616,7 @@
 	if (0 == strncmp(myword, _("PRE"), 3))
 	  sh_files_set_mask (mask, MODI_PREL, act);
+/* get content */
+	if (0 == strncmp(myword, _("TXT"), 3))
+	  sh_files_set_mask (mask, MODI_TXT, act);
 	
       }
@@ -1570,4 +1573,5 @@
   sl_strlcpy (theFile.fullpath, iname, PATH_MAX);
   theFile.attr_string = NULL;
+  theFile.link_path   = NULL;
 
   (void) relativeName;
@@ -1579,4 +1583,5 @@
     {
       if (theFile.attr_string) SH_FREE(theFile.attr_string);
+      if (theFile.link_path)   SH_FREE(theFile.link_path);
       SL_RETURN((0), _("sh_files_checkdir"));
     }
@@ -1586,5 +1591,6 @@
       SH_FREE(tmpname); 
       if (theFile.attr_string) SH_FREE(theFile.attr_string);
-      SL_RETURN((-1), _("sh_files_checkdir"));
+      if (theFile.link_path)   SH_FREE(theFile.link_path);
+     SL_RETURN((-1), _("sh_files_checkdir"));
     }
 
@@ -1596,4 +1602,5 @@
       SH_FREE(tmpname); 
       if (theFile.attr_string) SH_FREE(theFile.attr_string);
+      if (theFile.link_path)   SH_FREE(theFile.link_path);
       SL_RETURN((-1), _("sh_files_checkdir"));
     }
@@ -1618,4 +1625,5 @@
 
       if (theFile.attr_string) SH_FREE(theFile.attr_string);
+      if (theFile.link_path)   SH_FREE(theFile.link_path);
       SL_RETURN((-1), _("sh_files_checkdir"));
     }
@@ -1676,4 +1684,5 @@
       {
 	if (theFile.attr_string) SH_FREE(theFile.attr_string);
+	if (theFile.link_path)   SH_FREE(theFile.link_path);
 	SL_RETURN((0), _("sh_files_checkdir"));
       }
@@ -1871,4 +1880,5 @@
       {
 	if (theFile.attr_string) SH_FREE(theFile.attr_string);
+	if (theFile.link_path)   SH_FREE(theFile.link_path);
 	SL_RETURN((0), _("sh_files_checkdir"));
       }
@@ -1918,4 +1928,5 @@
 
   if (theFile.attr_string) SH_FREE(theFile.attr_string);
+  if (theFile.link_path)   SH_FREE(theFile.link_path);
   SH_FREE(tmpname);
 
@@ -2016,4 +2027,5 @@
   theFile.file_reported = (*reported);
   theFile.attr_string   = NULL;
+  theFile.link_path     = NULL;
 
   TPT(( 0, FIL__, __LINE__, _("msg=<checking file: %s>\n"),  fullpath));
@@ -2030,6 +2042,6 @@
       if (class == SH_LEVEL_ALLIGNORE && sh.flag.checkSum != SH_CHECK_INIT)
 	sh_hash_set_visited_true (fullpath);
-      if (theFile.attr_string) 
-	SH_FREE(theFile.attr_string);
+      if (theFile.attr_string) SH_FREE(theFile.attr_string);
+      if (theFile.link_path)   SH_FREE(theFile.link_path);
       SL_RETURN(SH_FILE_UNKNOWN, _("sh_files_filecheck"));
     }
@@ -2109,4 +2121,5 @@
 
   if (theFile.attr_string) SH_FREE(theFile.attr_string);
+  if (theFile.link_path)   SH_FREE(theFile.link_path);
 
   switch (theFile.c_mode[0]) 
Index: /trunk/src/sh_hash.c
===================================================================
--- /trunk/src/sh_hash.c	(revision 166)
+++ /trunk/src/sh_hash.c	(revision 167)
@@ -363,12 +363,11 @@
 
   sl_strlcpy(theFile->fullpath, p->fullpath, PATH_MAX);
-  if (p->linkpath != NULL && theFile->c_mode[0] == 'l')
-    {
-      sl_strlcpy(theFile->linkpath, p->linkpath, PATH_MAX);
+  if (p->linkpath != NULL /* && theFile->c_mode[0] == 'l' */)
+    {
+      theFile->link_path = sh_util_strdup(p->linkpath);
     }
   else
     {
-      theFile->linkpath[0] = '-';
-      theFile->linkpath[1] = '\0';
+      theFile->link_path = NULL;
     }
   sl_strlcpy(fileHash, p->theFile.checksum, KEY_LEN+1);
@@ -454,6 +453,6 @@
   SH_FREE(tmp);
   SH_FREE(str);
-  if (theFile->attr_string)
-    SH_FREE(theFile->attr_string);
+  if (theFile->attr_string) SH_FREE(theFile->attr_string);
+  if (theFile->link_path)   SH_FREE(theFile->link_path);
   SH_FREE(theFile);
 
@@ -541,6 +540,6 @@
 				   MSG_FI_MISS2, tmp, str);
 		  SH_FREE(str);
-		  if (theFile->attr_string)
-		    SH_FREE(theFile->attr_string);
+		  if (theFile->attr_string) SH_FREE(theFile->attr_string);
+		  if (theFile->link_path)   SH_FREE(theFile->link_path);
 		  SH_FREE(theFile);
 
@@ -1009,9 +1008,8 @@
   else
     {
-      len = sl_strlen(tmp)+1;
-      linkpath = SH_ALLOC(len);
-      (void) sl_strlcpy (linkpath, tmp, len);
-      if (len > 1 && linkpath[len-2] == '\n')
-	linkpath[len-2] = '\0';
+      len = sl_strlen(tmp);
+      linkpath = sh_util_strdup_l(tmp, len);
+      if (len > 0 && linkpath[len-1] == '\n')
+	linkpath[len-1] = '\0';
     }
 
@@ -1614,20 +1612,22 @@
   }
 
-  if (buf != NULL && buf->c_mode[0] == 'l' && buf->linkpath != NULL) 
+  if (buf != NULL /* && buf->c_mode[0] == 'l' */ && buf->link_path != NULL) 
     {  
 
-      old_len = sl_strlen(buf->linkpath);
+      old_len = sl_strlen(buf->link_path);
 #if defined(SH_STEALTH)
-      sh_do_encode(buf->linkpath, old_len);
-#endif
-      tmp = quote_string(buf->linkpath, old_len);
+      if (buf->c_mode[0] == 'l')
+	sh_do_encode(buf->link_path, old_len);
+#endif
+      tmp = quote_string(buf->link_path, old_len);
       tmp_len = sl_strlen(tmp);
 #if defined(SH_STEALTH)
-      sh_do_decode(buf->linkpath, old_len);
+      if (buf->c_mode[0] == 'l')
+	sh_do_decode(buf->link_path, old_len);
 #endif
 
       if (tmp && tmp_len <= MAX_PATH_STORE) 
 	{
-	  sl_strlcpy(linkpath, buf->linkpath, MAX_PATH_STORE+1);  
+	  sl_strlcpy(linkpath, buf->link_path, MAX_PATH_STORE+1);  
 	} 
       else 
@@ -1635,5 +1635,5 @@
 	  char hashbuf[KEYBUF_SIZE];
 	  sl_strlcpy(linkpath, 
-		     sh_tiger_hash (buf->linkpath,
+		     sh_tiger_hash (buf->link_path,
 				    TIGER_DATA, old_len,
 				    hashbuf, sizeof(hashbuf)),
@@ -1644,5 +1644,6 @@
       path_len = sl_strlen(linkpath);
 #if defined(SH_STEALTH)
-      sh_do_encode(linkpath, path_len);
+      if (buf->c_mode[0] == 'l')
+	sh_do_encode(linkpath, path_len);
 #endif
       tmp = quote_string(linkpath, path_len);
@@ -1873,6 +1874,6 @@
 	  f = sh_hash_create_ft (p, fileHash);
 	  sh_hash_pushdata_int (f, fileHash);
-	  if (f->attr_string)
-	    SH_FREE(f->attr_string);
+	  if (f->attr_string) SH_FREE(f->attr_string);
+	  if (f->link_path)   SH_FREE(f->link_path);
 	  SH_FREE(f);
 	}
@@ -1948,10 +1949,14 @@
     sh_hash_init();
 
+  tmpFile->link_path   = NULL;
+  tmpFile->attr_string = NULL;
+
   SH_MUTEX_LOCK(mutex_hash);
   p = sh_hash_have_it_int (newname);
   if (p)
     {
-      sl_strlcpy(tmpFile->fullpath, p->fullpath, PATH_MAX);
-      sl_strlcpy(tmpFile->linkpath, p->linkpath, PATH_MAX);
+      sl_strlcpy(tmpFile->fullpath,  p->fullpath, PATH_MAX);
+      if (p->linkpath)
+	tmpFile->link_path = sh_util_strdup (p->linkpath);
       tmpFile->size  = p->theFile.size;
       tmpFile->mtime = p->theFile.mtime;
@@ -2121,4 +2126,5 @@
 
   tmpFile.attr_string = NULL;
+  tmpFile.link_path   = NULL;
 
   sl_strlcpy(tmpFile.fullpath, key, PATH_MAX);
@@ -2141,11 +2147,12 @@
       tmpFile.c_mode[5] = 'w'; tmpFile.c_mode[6]  = 'x'; 
       tmpFile.c_mode[7] = 'r'; tmpFile.c_mode[8]  = 'w'; 
-      tmpFile.c_mode[9] = 'x'; tmpFile.c_mode[10] = '\0'; 
+      tmpFile.c_mode[9] = 'x'; tmpFile.c_mode[10] = '\0';
+      tmpFile.link_path = SH_ALLOC((size * 2) + 2);
       for (i = 0; i < size; ++i)
 	{
 	  p = sh_util_charhex (str[i],i2h);
-	  tmpFile.linkpath[2*i]   = p[0];
-	  tmpFile.linkpath[2*i+1] = p[1];
-	  tmpFile.linkpath[2*i+2] = '\0';
+	  tmpFile.link_path[2*i]   = p[0];
+	  tmpFile.link_path[2*i+1] = p[1];
+	  tmpFile.link_path[2*i+2] = '\0';
 	}
     }
@@ -2154,7 +2161,6 @@
       for (i = 0; i < 10; ++i) 
 	tmpFile.c_mode[i] = '-';
-      tmpFile.c_mode[10] = '\0'; 
-      tmpFile.linkpath[0] = '-'; 
-      tmpFile.linkpath[1] = '\0';
+      tmpFile.c_mode[10] = '\0';
+      tmpFile.link_path = sh_util_strdup("-");
     }
 
@@ -2165,4 +2171,5 @@
     sh_hash_pushdata (&tmpFile, SH_KEY_NULL);
 
+  if (tmpFile.link_path) SH_FREE(tmpFile.link_path);
   return;
 }
@@ -2178,5 +2185,6 @@
   char      * p;
   int         i;
-
+  char      * retval = NULL;
+  
   *size = 0;
 
@@ -2187,10 +2195,10 @@
       *val3 = tmpFile.ctime;
 
-      if (tmpFile.linkpath[0] != '-')
-	{
-	  len = strlen(tmpFile.linkpath);
+      if (tmpFile.link_path && tmpFile.link_path[0] != '-')
+	{
+	  len = strlen(tmpFile.link_path);
 
 	  p = SH_ALLOC((len/2)+1);
-	  i = sh_util_hextobinary (p, tmpFile.linkpath, len);
+	  i = sh_util_hextobinary (p, tmpFile.link_path, len);
 
 	  if (i == 0)
@@ -2198,5 +2206,5 @@
 	      *size = (len/2);
 	      p[*size] = '\0';
-	      return p;
+	      retval = p;
 	    }
 	  else
@@ -2204,5 +2212,4 @@
 	      SH_FREE(p);
 	      *size = 0;
-	      return NULL;
 	    }
 	}
@@ -2210,5 +2217,4 @@
 	{
 	  *size = 0;
-	  return NULL;
 	}
     }
@@ -2219,6 +2225,7 @@
       *val2 =  0;
       *val3 =  0;
-      return NULL;
-    }
+    }
+  if (tmpFile.link_path) SH_FREE(tmpFile.link_path);
+  return retval;
 }
 
@@ -2297,11 +2304,11 @@
   fp->fullpath  = fullpath;
 
-  if (buf->c_mode[0] == 'l')
+  if (buf->link_path)
     {  
-      len = sl_strlen(buf->linkpath);
+      len = sl_strlen(buf->link_path);
       if (len <= MAX_PATH_STORE) 
 	{
 	  linkpath = SH_ALLOC(len+1);
-	  sl_strlcpy(linkpath, buf->linkpath, len+1);
+	  sl_strlcpy(linkpath, buf->link_path, len+1);
 	} 
       else 
@@ -2309,5 +2316,5 @@
 	  linkpath = SH_ALLOC(KEY_LEN + 1);
 	  sl_strlcpy(linkpath, 
-		     sh_tiger_hash (buf->linkpath, TIGER_DATA, len,
+		     sh_tiger_hash (buf->link_path, TIGER_DATA, len,
 				    hashbuf, sizeof(hashbuf)), 
 		     KEY_LEN+1);
@@ -2490,7 +2497,7 @@
   sl_strlcat(msg, tmp, SH_BUFSIZE); 
 
-  if (theFile->c_mode[0] == 'l')
-    {
-      tmp_lnk     = sh_util_safe_name(theFile->linkpath);
+  if (theFile->c_mode[0] == 'l' || theFile->link_path != NULL)
+    {
+      tmp_lnk     = sh_util_safe_name(theFile->link_path);
       if (tmp_lnk)
 	{
@@ -2656,7 +2663,7 @@
   sl_strlcat(msg, tmp, SH_BUFSIZE); 
 
-  if (theFile->c_mode[0] == 'l')
-    {
-      tmp_lnk     = sh_util_safe_name(theFile->linkpath);
+  if (theFile->c_mode[0] == 'l' || theFile->link_path != NULL)
+    {
+      tmp_lnk     = sh_util_safe_name(theFile->link_path);
       if (tmp_lnk)
 	{
@@ -2862,10 +2869,10 @@
   if (p->theFile.c_mode[0] == 'l') 
     {
-      if (sl_strlen(theFile->linkpath) >= MAX_PATH_STORE) 
+      if (sl_strlen(theFile->link_path) >= MAX_PATH_STORE) 
 	{
 	  sl_strlcpy(linkHash, 
-		     sh_tiger_hash(theFile->linkpath, 
+		     sh_tiger_hash(theFile->link_path, 
 				   TIGER_DATA,
-				   sl_strlen(theFile->linkpath),
+				   sl_strlen(theFile->link_path),
 				   hashbuf, sizeof(hashbuf)), 
 		     MAX_PATH_STORE+1);
@@ -2874,5 +2881,5 @@
       else 
 	{
-	  sl_strlcpy(linkHash, theFile->linkpath, KEY_LEN + 1);
+	  sl_strlcpy(linkHash, theFile->link_path, KEY_LEN + 1);
 	  maxcomp = KEY_LEN;
 	}
@@ -3347,5 +3354,5 @@
       if ((modi_mask & MODI_LNK) != 0 && theFile->c_mode[0] == 'l')
 	{
-	  tmp_lnk     = sh_util_safe_name(theFile->linkpath);
+	  tmp_lnk     = sh_util_safe_name(theFile->link_path);
 	  tmp_lnk_old = sh_util_safe_name(p->linkpath);
 #ifdef SH_USE_XML
@@ -3364,8 +3371,9 @@
 	      if (p->linkpath != NULL && p->linkpath != notalink)
 		SH_FREE(p->linkpath);
-	      if (theFile->linkpath[0] == '-' && theFile->linkpath[1] == '\0')
+	      if (!(theFile->link_path) || 
+		  (theFile->link_path[0] == '-' && theFile->link_path[1] == '\0'))
 		p->linkpath = (char *)notalink;
 	      else
-		p->linkpath = sh_util_strdup(theFile->linkpath);
+		p->linkpath = sh_util_strdup(theFile->link_path);
 	    }
 #endif
@@ -3417,10 +3425,19 @@
 	      if (theFile->c_mode[0] == 'l') /* c_mode is already copied */
 		{
-		  sl_strlcpy(theFile->linkpath, p->linkpath, PATH_MAX);
+		  if (theFile->link_path)
+		    SH_FREE(theFile->link_path);
+		  if (p->linkpath)
+		    theFile->link_path = sh_util_strdup(p->linkpath);
+		  else
+		    theFile->link_path = sh_util_strdup("-");
 		}
 	      else
 		{
-		  theFile->linkpath[0] = '-';
-		  theFile->linkpath[1] = '\0';
+		  if (theFile->link_path)
+		    SH_FREE(theFile->link_path);
+		  if (p->linkpath && p->linkpath != notalink)
+		    theFile->link_path = sh_util_strdup(p->linkpath);
+		  else
+		    theFile->link_path = NULL;
 		}
 	      
@@ -3475,18 +3492,16 @@
 #endif
 	      
-	      if (theFile->c_mode[0] == 'l')
+	      if (theFile->c_mode[0] == 'l' || theFile->link_path)
 		{
                   if (p->linkpath != NULL && p->linkpath != notalink)
 		    SH_FREE(p->linkpath);
-		  p->linkpath = sh_util_strdup(theFile->linkpath);
+		  p->linkpath = sh_util_strdup(theFile->link_path);
 		}
 	      else
 		{
 	          if (p->linkpath != NULL && p->linkpath != notalink) {
-		    p->linkpath[0] = '-';
-		    p->linkpath[1] = '\0';
-                  } else {
-		    p->linkpath = (char *)notalink;
-                  }
+		    SH_FREE(p->linkpath);
+		  }
+		  p->linkpath = (char *)notalink;
 		}
 	      
Index: /trunk/src/sh_kern.c
===================================================================
--- /trunk/src/sh_kern.c	(revision 166)
+++ /trunk/src/sh_kern.c	(revision 167)
@@ -915,4 +915,5 @@
   CLEAR_SH_FFLAG_REPORTED(theFile.file_reported);
   theFile.attr_string = NULL;
+  theFile.link_path   = NULL;
   
   status = sh_unix_getinfo (ShDFLevel[SH_ERR_T_RO], 
@@ -928,5 +929,5 @@
 		       tmp);
       SH_FREE(tmp);
-      return;
+      goto out;
     }
 
@@ -940,4 +941,7 @@
     }
 
+ out:
+  if (theFile.attr_string) SH_FREE(theFile.attr_string);
+  if (theFile.link_path)   SH_FREE(theFile.link_path);
   return;
 }
Index: /trunk/src/sh_suidchk.c
===================================================================
--- /trunk/src/sh_suidchk.c	(revision 166)
+++ /trunk/src/sh_suidchk.c	(revision 167)
@@ -1032,4 +1032,5 @@
 	    CLEAR_SH_FFLAG_REPORTED(theFile.file_reported);
 	    theFile.attr_string = NULL;
+	    theFile.link_path   = NULL;
 	    
 	    status = sh_unix_getinfo (ShDFLevel[SH_ERR_T_RO], 
@@ -1161,6 +1162,6 @@
 	      }
 	    SH_FREE(tmp);
-	    if (theFile.attr_string)
-	      SH_FREE(theFile.attr_string);
+	    if (theFile.attr_string) SH_FREE(theFile.attr_string);
+	    if (theFile.link_path)   SH_FREE(theFile.link_path);
 	  }
       }
Index: /trunk/src/sh_tiger0.c
===================================================================
--- /trunk/src/sh_tiger0.c	(revision 166)
+++ /trunk/src/sh_tiger0.c	(revision 167)
@@ -25,4 +25,5 @@
 #include "sh_utils.h"
 #include "sh_pthread.h"
+#include "sh_string.h"
 
 #define PRIV_MAX  32768
@@ -114,4 +115,5 @@
 {
   SL_TICKET  fd;
+  sh_string * content = NULL;
   int  i, j, tt;
   int  count = 0;
@@ -159,5 +161,6 @@
       if (what > TIGER_FILE)
 	{
-	  fd = what;
+	  fd      = what;
+	  content = sl_get_content(fd);
 	  TPT((0,FIL__, __LINE__, _("msg=<TIGER_FD>, fd=<%ld>\n"), fd));
 	}
@@ -247,4 +250,7 @@
 	    SL_RETURN( NULL, _("sh_tiger_hash_val"));
 	  }
+
+	if (content)
+	  sh_string_cat_lchar(content, (char*)buffer, count);
 
 	bcount += count;
@@ -843,4 +849,5 @@
   uid_t   euid;
   UINT64  bcount = 0;
+  sh_string * content;
 
   unsigned long pages_read;
@@ -867,4 +874,6 @@
 
   pages_read = 0;
+
+  content = sl_get_content(fd);
 
   /* Iterate over full file contents.  */
@@ -902,4 +911,7 @@
 	  return -1;
 	}
+
+      if (content)
+	sh_string_cat_lchar(content, buffer, n);
 
       bcount += n;
@@ -1360,4 +1372,5 @@
   uid_t  euid;
   UINT64 bcount = 0;
+  sh_string * content;
 
   unsigned long pages_read;
@@ -1386,4 +1399,6 @@
 
   pages_read = 0;
+
+  content = sl_get_content(fd);
 
   while (1 == 1) {
@@ -1422,4 +1437,7 @@
 	  return -1;
 	}
+
+      if (content)
+	sh_string_cat_lchar(content, buffer, n);
 
       bcount += n;
Index: /trunk/src/sh_unix.c
===================================================================
--- /trunk/src/sh_unix.c	(revision 166)
+++ /trunk/src/sh_unix.c	(revision 167)
@@ -3062,8 +3062,10 @@
       
        /* return */
+      if (tmpFile.link_path)   SH_FREE(tmpFile.link_path);
       SL_RETURN( 0, _("sh_unix_checksum_size"));
     }
 
  out:
+  if (tmpFile.link_path)   SH_FREE(tmpFile.link_path);
   sl_strlcpy(fileHash, SH_KEY_NULL, KEY_LEN+1);
   SL_RETURN( -1, _("sh_unix_checksum_size"));
@@ -3279,5 +3281,6 @@
   int           fd;
   int           fstat_return;
-
+  sh_string   * content = NULL;
+      
   time_t        tend;
   time_t        tstart;
@@ -3302,4 +3305,6 @@
   fstat_return = -1;
   rval_open    = -1;
+
+  theFile->link_path = NULL;
 
   if (stat_return == 0 && S_ISREG(buf.st_mode)) 
@@ -3396,4 +3401,10 @@
 	      char hashbuf[KEYBUF_SIZE];
 	      UINT64 length_nolim = TIGER_NOLIM;
+
+	      if ((theFile->check_mask & MODI_TXT) != 0 && fbuf.st_size < SH_TXT_MAX)
+		{
+		  sl_init_content (rval_open, fbuf.st_size);
+		}
+
 	      sl_strlcpy(fileHash,
 			 sh_tiger_generic_hash (theFile->fullpath, 
@@ -3402,4 +3413,7 @@
 						hashbuf, sizeof(hashbuf)),
 			 KEY_LEN+1);
+
+	      content = sl_get_content(rval_open);
+
 	      if ((theFile->check_mask & MODI_SGROW) != 0)
 		{
@@ -3439,4 +3453,10 @@
 	      char hashbuf[KEYBUF_SIZE];
 	      UINT64 length_nolim = TIGER_NOLIM;
+
+	      if ((theFile->check_mask & MODI_TXT) != 0 && fbuf.st_size < SH_TXT_MAX)
+		{
+		  sl_init_content (rval_open, fbuf.st_size);
+		}
+
 	      sl_strlcpy(fileHash, 
 			 sh_tiger_generic_hash (theFile->fullpath, rval_open, 
@@ -3445,4 +3465,7 @@
 						hashbuf, sizeof(hashbuf)),
 			 KEY_LEN + 1);
+
+	      content = sl_get_content(rval_open);
+
 	      if ((theFile->check_mask & MODI_SGROW) != 0) 
 		{
@@ -3617,5 +3640,4 @@
   if (theFile->c_mode[0] == 'l') 
     {
-
       linknamebuf = SH_ALLOC(PATH_MAX);
 
@@ -3637,99 +3659,109 @@
 	  SH_FREE(tmp2);
 	  SH_FREE(linknamebuf);
-	  theFile->linkpath[0] = '-';
-	  theFile->linkpath[1] = '\0';
+	  theFile->link_path = sh_util_strdup("-");
 	  SL_RETURN((-1),_("sh_unix_getinfo"));
 	}
 
-    if (linknamebuf[0] == '/') 
-      {
-	sl_strlcpy (theFile->linkpath, linknamebuf, PATH_MAX);
-      } 
-    else 
-      {
-	tmp = sh_util_dirname(theFile->fullpath);
-	if (tmp) {
-	  sl_strlcpy (theFile->linkpath, tmp, PATH_MAX);
+      if (linknamebuf[0] == '/') 
+	{
+	  theFile->link_path = sh_util_strdup (linknamebuf);
+	} 
+      else 
+	{
+	  tmp = sh_util_dirname(theFile->fullpath);
+	  if (tmp) {
+	    theFile->link_path = SH_ALLOC(PATH_MAX);
+	    sl_strlcpy (theFile->link_path, tmp, PATH_MAX);
+	    SH_FREE(tmp);
+	  } else {
+	    theFile->link_path = SH_ALLOC(PATH_MAX);
+	    theFile->link_path[0] = '\0';
+	  }
+	  /*
+	   * Only attach '/' if not root directory. Handle "//", which
+	   * according to POSIX is implementation-defined, and may be
+	   * different from "/" (however, three or more '/' will collapse
+	   * to one).
+	   */
+	  tmp = theFile->link_path; while (*tmp == '/') ++tmp;
+	  if (*tmp != '\0')
+	    {
+	      sl_strlcat (theFile->link_path, "/", PATH_MAX);
+	    }
+	  sl_strlcat (theFile->link_path, linknamebuf, PATH_MAX);
+	}
+      
+      /* stat the link
+       */
+      stat_return = retry_lstat (FIL__, __LINE__, theFile->link_path, &lbuf); 
+      
+      /* check for error
+       */
+      if (stat_return != 0) 
+	{ 
+	  stat_return = errno;
+	  tmp  = sh_util_safe_name (theFile->fullpath);
+	  tmp2 = sh_util_safe_name (theFile->link_path);
+	  if (stat_return != ENOENT)
+	    { 
+	      char errbuf[SH_ERRBUF_SIZE];
+	      sh_error_handle (level, FIL__, __LINE__, stat_return, 
+			       MSG_FI_LSTAT,
+			       sh_error_message (stat_return,errbuf, sizeof(errbuf)), 
+			       tmp2);
+	    }
+	  else 
+	    {
+	      /* a dangling link -- everybody seems to have plenty of them 
+	       */
+	      sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_DLNK,
+			       tmp, tmp2);
+	    }
+	  theFile->linkisok = BAD;
 	  SH_FREE(tmp);
-	} else {
-	  theFile->linkpath[0] = '\0';
-	}
-	/*
-	 * Only attach '/' if not root directory. Handle "//", which
-	 * according to POSIX is implementation-defined, and may be
-	 * different from "/" (however, three or more '/' will collapse
-	 * to one).
-	 */
-	tmp = theFile->linkpath; while (*tmp == '/') ++tmp;
-	if (*tmp != '\0')
-	  {
-	    sl_strlcat (theFile->linkpath, "/", PATH_MAX);
-	  }
-	sl_strlcat (theFile->linkpath, linknamebuf, PATH_MAX);
-      }
-    
-    /* stat the link
-     */
-    stat_return = retry_lstat (FIL__, __LINE__, theFile->linkpath, &lbuf); 
-
-    /* check for error
-     */
-    if (stat_return != 0) 
-      { 
-	stat_return = errno;
-	tmp  = sh_util_safe_name (theFile->fullpath);
-	tmp2 = sh_util_safe_name (theFile->linkpath);
-	if (stat_return != ENOENT)
-	  { 
-	    char errbuf[SH_ERRBUF_SIZE];
-	    sh_error_handle (level, FIL__, __LINE__, stat_return, 
-			     MSG_FI_LSTAT,
-			     sh_error_message (stat_return,errbuf, sizeof(errbuf)), 
-			     tmp2);
-	  }
-	else 
-	  {
-	    /* a dangling link -- everybody seems to have plenty of them 
-	     */
-	    sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_DLNK,
-			     tmp, tmp2);
-	  }
-	theFile->linkisok = BAD;
-	SH_FREE(tmp);
-	SH_FREE(tmp2);
-	SH_FREE(linknamebuf);
-	/* 
-	 * changed Tue Feb 10 16:16:13 CET 2004:
-	 *  add dangling symlinks into database
-	 * SL_RETURN((-1),_("sh_unix_getinfo")); 
-	 */
-	theFile->linkmode = 0;
-	SL_RETURN((0),_("sh_unix_getinfo")); 
-      }
-
-    theFile->linkisok = GOOD;
+	  SH_FREE(tmp2);
+	  SH_FREE(linknamebuf);
+	  /* 
+	   * changed Tue Feb 10 16:16:13 CET 2004:
+	   *  add dangling symlinks into database
+	   * SL_RETURN((-1),_("sh_unix_getinfo")); 
+	   */
+	  theFile->linkmode = 0;
+	  SL_RETURN((0),_("sh_unix_getinfo")); 
+	}
       
-
-    /* --- Determine file type. ---
-     */
-    sh_unix_getinfo_type (&lbuf, &type, theFile->link_c_mode);
-    theFile->type = type;
-  
-    /* --- Determine permissions. ---
-     */
-    sh_unix_getinfo_mode (&lbuf, &mode, theFile->link_c_mode);
-    theFile->linkmode = lbuf.st_mode;
-
-    /* --- Output the link. ---
-     */
-    if (theFile->linkisok == GOOD) 
-      {
-	tmp2 = sh_util_safe_name (linknamebuf);      
-	sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_LLNK,
-			 theFile->link_c_mode, tmp2);
-	SH_FREE(tmp2);
-      }
-    SH_FREE(linknamebuf);
-  }  
+      theFile->linkisok = GOOD;
+      
+      
+      /* --- Determine file type. ---
+       */
+      sh_unix_getinfo_type (&lbuf, &type, theFile->link_c_mode);
+      theFile->type = type;
+      
+      /* --- Determine permissions. ---
+       */
+      sh_unix_getinfo_mode (&lbuf, &mode, theFile->link_c_mode);
+      theFile->linkmode = lbuf.st_mode;
+      
+      /* --- Output the link. ---
+       */
+      if (theFile->linkisok == GOOD) 
+	{
+	  tmp2 = sh_util_safe_name (linknamebuf);      
+	  sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_LLNK,
+			   theFile->link_c_mode, tmp2);
+	  SH_FREE(tmp2);
+	}
+      SH_FREE(linknamebuf);
+    }
+  else /* not a link */
+    {
+      if (content)
+	{
+	  sh_util_base64_enc_alloc (&(theFile->link_path), 
+				    sh_string_str(content), 
+				    sh_string_len(content));
+	}
+    } 
   SL_RETURN((0),_("sh_unix_getinfo"));
 }
Index: /trunk/src/sh_utils.c
===================================================================
--- /trunk/src/sh_utils.c	(revision 166)
+++ /trunk/src/sh_utils.c	(revision 167)
@@ -283,5 +283,5 @@
     {
       p   = SH_ALLOC (len + 1);
-      (void) sl_strlcpy (p, str, len+1);
+      (void) memcpy (p, str, len+1);
     }
   else
@@ -303,5 +303,5 @@
   len = sl_strlen(str);
   p   = SH_ALLOC (len + 1);
-  (void) sl_strlcpy (p, str, len+1);
+  (void) memcpy (p, str, len+1);
 
   SL_RETURN( p, _("sh_util_strdup"));
@@ -2084,4 +2084,167 @@
 }
 
+static const char bto64_0[] = N_("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789()");
+static char bto64[65] = { '\0' };
+
+  
+size_t sh_util_base64_enc (unsigned char * out, const unsigned char * instr, 
+			   size_t lin)
+{
+  int             ll;
+  unsigned char   a, b, c;
+  size_t          len  = 0;
+  size_t          j    = 0;
+
+ start:
+  if (bto64[0] != '\0')
+    {
+      if (instr && *instr)
+	{
+	  if (lin == 0)
+	    lin = strlen((char *)instr);
+
+	  do {
+	    ll = 0;
+
+	    if (len < lin) 
+	      { a = *instr; ++instr; ++len; ++ll; }
+	    else 
+	      { a = 0; }
+	    if (len < lin) 
+	      { b = *instr; ++instr; ++len; ++ll; }
+	    else 
+	      { b = 0; }
+	    if (len < lin) 
+	      { c = *instr; ++instr; ++len; ++ll; }
+	    else 
+	      { c = 0; }
+
+	    *out = bto64[ a >> 2 ];
+	    ++j; ++out;
+	    *out = bto64[ ((a & 0x03) << 4) | ((b & 0xf0) >> 4) ];
+	    ++j; ++out;
+	    *out = (unsigned char) (ll > 1 ? bto64[ ((b & 0x0f) << 2) | ((c & 0xc0) >> 6) ] : '?');
+	    ++j; ++out;
+	    *out = (unsigned char) (ll > 2 ? bto64[ c & 0x3f ] : '?');
+	    ++j; ++out;
+	  } while (len < lin);
+	}
+      *out = '\0';
+      return j;
+    }
+
+  memcpy(bto64, _(bto64_0), 65);
+  goto start;
+}
+
+size_t sh_util_base64_enc_alloc (char **out, const char *in, size_t inlen)
+{
+  size_t outlen = SH_B64_SIZ(inlen);
+
+  if (inlen > outlen) /* overflow */
+    {
+      *out = NULL;
+      return 0;
+    }
+
+  *out = SH_ALLOC(outlen);
+  return sh_util_base64_enc((unsigned char *)*out, (unsigned char *)in, inlen);
+}
+
+size_t sh_util_base64_dec (unsigned char *out, const unsigned char *in, 
+			   size_t lin)
+{
+  size_t i;
+  unsigned char c;
+  unsigned char b;
+  size_t lout = 0;
+  int    w = 0;
+
+  if (out && in)
+    {
+      if (lin == 0)
+	lin = strlen((char *)in);
+
+      for (i = 0; i < lin; i++)
+	{
+	  c = *in; ++in;
+	  b = 0;
+	  
+	  if ((c >= 'A') && (c <= 'Z'))
+	    {
+	      b = (c - 'A');
+	    }
+	  else if ((c >= 'a') && (c <= 'z'))
+	    {
+	      b = (c - 'a' + 26);
+	    }
+	  else if ((c >= '0') && (c <= '9'))
+	    {
+	      b = (c - '0' + 52);
+	    }
+	  else if (c == '(' || c == '+')
+	    {
+	      b = 62;
+	    }
+	  else if (c == ')' || c == '/')
+	    {
+	      b = 64;
+	    }
+	  else if (c == '?' || c == '=')
+	    {
+	      /* last byte was written to, but will now get
+	       * truncated
+	       */
+	      if (lout > 0) --lout;
+	      break;
+	    }
+	  
+	  if (w == 0)
+	    {
+	      *out = (b << 2) & 0xfc;
+	      ++lout;
+	    }
+	  else if (w == 1)
+	    {
+	      *out |= (b >> 4) & 0x03;
+	      ++out;
+	      *out = (b << 4) & 0xf0;
+	      ++lout;
+	    }
+	  else if (w == 2)
+	    {
+	      *out |= (b >> 2) & 0x0f;
+	      ++out;
+	      *out = (b << 6) & 0xc0;
+	      ++lout;
+	    }
+	  else if (w == 3)
+	    {
+	      *out |= b & 0x3f;
+	      ++out;
+	    }
+	  
+	  ++w;
+	  
+	  if (w == 4)
+	    {
+	      w = 0;
+	    }
+	}
+      *out = '\0';
+    }
+  return lout;
+}
+
+size_t sh_util_base64_dec_alloc (unsigned char **out, const unsigned char *in, 
+				 size_t lin)
+{
+  size_t lout = 3 * (lin / 4) + 2;
+
+  *out = SH_ALLOC(lout);
+
+  return sh_util_base64_dec (*out, in, lin);
+}
+
 
 #ifdef HAVE_REGEX_H
Index: /trunk/src/slib.c
===================================================================
--- /trunk/src/slib.c	(revision 166)
+++ /trunk/src/slib.c	(revision 167)
@@ -56,4 +56,5 @@
 #include "sh_static.h"
 #include "sh_pthread.h"
+#include "sh_string.h"
 
 #undef  FIL__
@@ -1504,4 +1505,5 @@
   int fd;               /* The file descriptor. */
   char * path;          /* The file path.       */
+  sh_string * content;  /* The file content     */
 } SL_OFILE; 
 
@@ -1624,6 +1626,7 @@
 
   sl_strlcpy (ofiles[fd]->path, filename, len);
-  ofiles[fd]->ticket = ticket;
-  ofiles[fd]->fd     = fd;
+  ofiles[fd]->ticket  = ticket;
+  ofiles[fd]->fd      = fd;
+  ofiles[fd]->content = NULL;
 
   SL_IRETURN(ticket, _("sl_make_ticket"));
@@ -1862,6 +1865,7 @@
 
   sl_strlcpy (ofiles[fd]->path, filename, len);
-  ofiles[fd]->ticket = ticket;
-  ofiles[fd]->fd     = fd;
+  ofiles[fd]->ticket  = ticket;
+  ofiles[fd]->fd      = fd;
+  ofiles[fd]->content = NULL;
 
   SL_IRETURN(ticket, _("sl_open_file"));
@@ -1981,4 +1985,34 @@
 }
 
+int sl_init_content (SL_TICKET ticket, size_t size)
+{
+  int fd;
+
+  if (SL_ISERROR(fd = sl_read_ticket(ticket)))
+    return (fd);
+
+  if (ofiles[fd] == NULL || fd != ofiles[fd]->fd || fd < 0)
+    return (SL_EINTERNAL);
+
+  if (ofiles[fd]->content)
+    sh_string_destroy(&(ofiles[fd]->content));
+  ofiles[fd]->content = sh_string_new(size);
+
+  return SL_ENONE;
+}
+
+sh_string * sl_get_content (SL_TICKET ticket)
+{
+  int fd;
+
+  if (SL_ISERROR(fd = sl_read_ticket(ticket)))
+    return (NULL);
+
+  if (ofiles[fd] == NULL || fd != ofiles[fd]->fd || fd < 0)
+    return (NULL);
+
+  return (ofiles[fd]->content);
+}
+
 int sl_close (SL_TICKET ticket) 
 {
@@ -2001,4 +2035,6 @@
   if (ofiles[fd] != NULL)
     {
+      if (ofiles[fd]->content)
+	sh_string_destroy(&(ofiles[fd]->content));
       (void) free(ofiles[fd]->path);
       (void) free(ofiles[fd]);
@@ -2015,4 +2051,6 @@
       if (ofiles[fd] != NULL && fd != except)
 	{
+	  if (ofiles[fd]->content)
+	    sh_string_destroy(&(ofiles[fd]->content));
 	  if (ofiles[fd]->path != NULL)
 	    (void) free(ofiles[fd]->path);
