KTempDir ?

Joseph Wenninger jowenn at kde.org
Wed Feb 5 01:52:29 GMT 2003


Hi

I would need something like KTempFile for an appliaction, I'm working at
(kexi), but for directories. I think that could be usefull for others
too, so I decided to create a KTempDir class.

I enclose a patchfile for the kdelibs build system and the fakes.c file.
The fakes.c part of the patch should provide a platform independent
mkdtemp (most of the code taken from the already existing mkstemps.

Additionaly I enclose the two cpp and h file which does the real work ;)

What do you think. Would it be usefull to include something like that
into kdecore ? Any major design flaws ?

Kind regards
Joseph Wenninger


-------------- next part --------------
Index: configure.in.in
===================================================================
RCS file: /home/kde/kdelibs/configure.in.in,v
retrieving revision 1.104
diff -u -3 -p -r1.104 configure.in.in
--- configure.in.in	10 Jan 2003 15:07:10 -0000	1.104
+++ configure.in.in	4 Feb 2003 21:16:28 -0000
@@ -102,6 +102,7 @@ AC_CHECK_SETENV
 AC_CHECK_UNSETENV
 AC_CHECK_RANDOM
 AC_CHECK_MKSTEMPS
+AC_CHECK_MKDTEMP	
 AC_CHECK_FUNCS(strtoll socket seteuid setegid strfmon stpcpy gettimeofday)
 
 AH_BOTTOM([
Index: admin/acinclude.m4.in
===================================================================
RCS file: /home/kde/kde-common/admin/acinclude.m4.in,v
retrieving revision 2.333
diff -u -3 -p -r2.333 acinclude.m4.in
--- admin/acinclude.m4.in	22 Jan 2003 12:48:06 -0000	2.333
+++ admin/acinclude.m4.in	4 Feb 2003 21:16:33 -0000
@@ -2167,6 +2167,20 @@ mkstemps("/tmp/aaaXXXXXX", 6);
 	[MKSTEMPS])
 ])
 
+AC_DEFUN(AC_CHECK_MKDTEMP,
+[
+	KDE_CHECK_FUNC_EXT(mkdtemp, [
+#include <stdlib.h>
+#include <unistd.h>
+],
+	[
+mkdtemp("/tmp/aaaXXXXXX");
+],
+	[char *mkdtemp(char *)],
+	[MKDTEMP])
+])
+
+
 AC_DEFUN(AC_CHECK_RES_INIT,
 [
   AC_MSG_CHECKING([if res_init needs -lresolv])
Index: kdecore/Makefile.am
===================================================================
RCS file: /home/kde/kdelibs/kdecore/Makefile.am,v
retrieving revision 1.321
diff -u -3 -p -r1.321 Makefile.am
--- kdecore/Makefile.am	30 Jan 2003 23:15:24 -0000	1.321
+++ kdecore/Makefile.am	4 Feb 2003 21:16:53 -0000
@@ -54,7 +54,7 @@ include_HEADERS = kconfig.h kconfigdata.
 	klargefile.h kmultipledrag.h kgenericfactory.h kgenericfactory.tcc ktypelist.h \
 	ksortablevaluelist.h kdebugclasses.h kclipboard.h kcalendarsystem.h \
 	kcalendarsystemfactory.h kmacroexpander.h kmanagerselection.h \
-	kidna.h
+	kidna.h ktempdir.h
 
 libkdefakes_la_SOURCES = fakes.c vsnprintf.c
 libkdefakes_la_LDFLAGS = -version-info 6:0:2
@@ -104,7 +104,8 @@ libkdecore_la_SOURCES = libintl.cpp kapp
 	kdeversion.cpp kdebugdcopiface.cpp kdebugdcopiface.skel \
 	kcalendarsystem.cpp kcalendarsystemgregorian.cpp \
 	kcalendarsystemhijri.cpp kcalendarsystemhebrew.cpp \
-	kcalendarsystemfactory.cpp kmacroexpander.cpp kidna.cpp
+	kcalendarsystemfactory.cpp kmacroexpander.cpp kidna.cpp \
+	ktempdir.cpp
 
 libkdecore_la_LDFLAGS = $(QT_LDFLAGS) $(KDE_RPATH) $(KDE_MT_LDFLAGS) $(X_LDFLAGS) $(USER_LDFLAGS) -version-info 6:0:2 -no-undefined
 libkdecore_la_LIBADD = malloc/libklmalloc.la $(SVGICON_LIB) ../dcop/libDCOP.la ../libltdl/libltdlc.la $(LIB_XEXT) $(LIBRESOLV) $(LIBUTIL) $(LIBART_LIBS) ../kdefx/libkdefx.la
Index: kdecore/fakes.c
===================================================================
RCS file: /home/kde/kdelibs/kdecore/fakes.c,v
retrieving revision 1.15
diff -u -3 -p -r1.15 fakes.c
--- kdecore/fakes.c	28 Dec 2002 15:21:42 -0000	1.15
+++ kdecore/fakes.c	4 Feb 2003 21:16:53 -0000
@@ -231,6 +231,71 @@ int mkstemp (char* _template)
 }
 #endif
 
+#ifndef HAVE_MKDTEMP
+
+#ifndef HAVE_MKSTEMPS
+#include <sys/types.h>
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#endif
+
+/* Generate a unique temporary directory name from TEMPLATE.
+
+   TEMPLATE has the form:
+
+   <path>/ccXXXXXX
+
+
+   The last six characters of TEMPLATE must be "XXXXXX";
+   they are replaced with a string that makes the filename unique.
+
+   Returns a file descriptor open on the file for reading and writing.  */
+
+char* mkdtemp (char* _template)
+{
+  static const char letters[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+  char *XXXXXX;
+  int len;
+  int count;
+  int value;
+
+  len = strlen (_template);
+
+  if ((int) len < 6 || strncmp (&_template[len - 6], "XXXXXX", 6))
+      return 0;
+
+  XXXXXX = &_template[len - 6];
+
+  value = rand();
+  for (count = 0; count < 256; ++count)
+  {
+      int v = value;
+
+      /* Fill in the random bits.  */
+      XXXXXX[0] = letters[v % 62];
+      v /= 62;
+      XXXXXX[1] = letters[v % 62];
+      v /= 62;
+      XXXXXX[2] = letters[v % 62];
+      v /= 62;
+      XXXXXX[3] = letters[v % 62];
+      v /= 62;
+      XXXXXX[4] = letters[v % 62];
+      v /= 62;
+      XXXXXX[5] = letters[v % 62];
+
+      /* This is a random value.  It is only necessary that the next
+	 TMP_MAX values generated by adding 7777 to VALUE are different
+	 with (module 2^32).  */
+      value += 7777;
+
+      if (!mkdir(_template,0700))
+	return _template;	
+    }
+    return 0;
+}
+#endif
 
 #ifndef HAVE_REVOKE
 #include <errno.h>
-------------- next part --------------
/* 
   This file is part of the KDE libraries
   Copyright (c) 2003 Joseph Wenninger <jowenn at kde.org>
   
   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License version 2 as published by the Free Software Foundation.
   
   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.
   
   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.
*/

#ifndef _KTEMPDIR_H_
#define _KTEMPDIR_H_

#include <qstring.h>
#include <stdio.h>
#include <errno.h>

class QDir;
class KTempDirPrivate;

/**
 * The KTempDir class creates a unique directory for temporary use.
 *
 * This is especially useful if you need to create a directory in a world
 * writable directory like /tmp without being vulnerable to so called
 * symlink attacks.
 *
 * KDE applications, however, shouldn't create files or directories in /tmp in the first 
 * place but use the "tmp" resource instead. The standard KTempDir
 * constructor will do that by default.
 *
 * To create a temporary directory that starts with a certain name
 * in the "tmp" resource, one should use:
 * KTempDir(locateLocal("tmp", prefix));
 *
 * KTempFile does not create any missing directories, but locateLocal() does.
 *
 * See also @ref KStandardDirs
 *
 * @author Joseph Wenninger <jowenn at kde.org>
 */
class KTempDir
{
public:
   /**
    * Creates a temporary directory with the name:
    *  <directoryPrefix><six letters>
    *
    * The default @p directoryPrefix is "$KDEHOME/tmp-$HOST/appname"
    * @param directoryPrefix the prefix of the file name, or QString::null
    *        for the default value
    **/
   KTempDir(QString directoryPrefix=QString::null, 
             int mode = 0700 );


   /**
    * The destructor deletes the directory and it's contents if autoDelete is enabled
    **/
   ~KTempDir();

   /**
    * Turn automatic deletion on or off.
    * Automatic deletion is off by default.
    * @param autoDelete true to turn automatic deletion on
    **/
   void setAutoDelete(bool autoDelete) { bAutoDelete = autoDelete; }

   /**
    * Returns the status of the directory creation  based on errno. (see errno.h) 
    * 0 means OK.
    *
    * You should check the status after object creation to check 
    * whether a directory could be created in the first place.
    *
    * @return the errno status, 0 means ok
    **/
   int status() const;

   /**
    * Returns the full path and name of the directory.
    * @return The name of the file, or QString::null if creating the
    *         directory has failed or the directory has been unlinked
    **/
   QString name() const;
   
   
   /**
    * Returns the @ref QDir* of the temporary directory.
    * @return QDir directory information of the directory or 0 if their is no managed directory
    * The caller has to free the pointer open for writing to the 
    **/
   QDir *qDir();

   /**
    * Deletes the directory recursively
    **/
   void unlink();   

   /**
    * @return true if a temporary directory has successfully been created and not been unlinked yet
    */
   bool existing() const;
protected:

   bool create(const QString &directoryPrefix,  int mode);

   void setError(int error) { mError = error; }
private:
   int mError;
   QString mTmpName;
   bool bExisting;
   bool bAutoDelete;

   KTempDirPrivate *d;
};

#endif
-------------- next part --------------
/*
 *
 *  This file is part of the KDE libraries
 *  Copyright (c) 2003 Joseph Wenninger <jowenn at kde.org>
 *
 * $Id: $
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Library General Public
 *  License version 2 as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Library General Public License for more details.
 *
 *  You should have received a copy of the GNU Library General Public License
 *  along with this library; see the file COPYING.LIB.  If not, write to
 *  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 *  Boston, MA 02111-1307, USA.
 **/

#include <config.h>

#include <sys/types.h>

#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif

#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>

#ifdef HAVE_TEST
#include <test.h>
#endif
#ifdef HAVE_PATHS_H
#include <paths.h>
#endif

#ifndef _PATH_TMP
#define _PATH_TMP "/tmp"
#endif

#include <qdatetime.h>
#include <qdir.h>

#include "kglobal.h"
#include "kapplication.h"
#include "kinstance.h"
#include "ktempdir.h"
#include "kstandarddirs.h"
#include "kprocess.h"

KTempDir::KTempDir(QString directoryPrefix, int mode)
{
   bAutoDelete = false;
   bExisting = false;
   if (directoryPrefix.isEmpty())
   {
      directoryPrefix = locateLocal("tmp", KGlobal::instance()->instanceName());
   }
   (void) create(directoryPrefix , mode);
}

bool
KTempDir::create(const QString &directoryPrefix, int mode)
{
   // make sure the random seed is randomized
   (void) KApplication::random();

   QCString nme = QFile::encodeName(directoryPrefix) + "XXXXXX";
   if(mkdtemp(nme.data()) == 0)
   {
       // Recreate it for the warning, mkdtemps emptied it
       QCString nme = QFile::encodeName(directoryPrefix) + "XXXXXX";
       qWarning("KTempDir: Error trying to create %s: %s", nme.data(), strerror(errno));
       mError = errno;
       mTmpName = QString::null;
       return false;
   }

   // got a return value != 0

   mTmpName = QFile::decodeName(nme);

   mode_t tmp = 0;
   mode_t umsk = umask(tmp);
   umask(umsk);
   chmod(nme, mode&(~umsk));

   // Success!
   bExisting = true;

   // Set uid/gid (neccesary for SUID programs)
   chown(nme, getuid(), getgid());
   return true;
}

KTempDir::~KTempDir()
{
   if (bAutoDelete)
      unlink();
}

int
KTempDir::status() const
{
   return mError;
}

QString
KTempDir::name() const
{
   return mTmpName;
}

bool
KTempDir::existing() const
{
   return bExisting;
}

QDir *
KTempDir::qDir()
{
   if (bExisting) return new QDir(mTmpName);
   return 0;
}

void
KTempDir::unlink()
{
   if (!bExisting) return;
   QString rmstr("rm -rf ");
   rmstr += KProcess::quote(mTmpName);
   ::system( QFile::encodeName(rmstr) );

   bExisting=false;
   mError=0;
}




More information about the kde-core-devel mailing list