searchengine/util/cpixtools/src/cpixfstools.cpp
changeset 0 671dee74050a
child 2 6c1a2771f4b7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/searchengine/util/cpixtools/src/cpixfstools.cpp	Mon Apr 19 14:40:16 2010 +0300
@@ -0,0 +1,798 @@
+/*
+* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: 
+*
+*/
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <string>
+#include <sstream>
+
+#include "cpixfstools.h"
+#include "cpixstrtools.h"
+
+
+namespace
+{
+    const char DIR_SEPARATOR = '\\';
+}
+
+
+
+namespace Cpt
+{
+
+    int getparent(char       * parent, 
+                  size_t       bufSize,
+                  const char * child)
+    {
+        size_t
+            len = strlen(child);
+	if (child[len-1] == '\\' ||
+            child[len-1] == '/') {
+            len--;
+	}
+
+	size_t
+            i = len-1;
+
+	while (1)/*(i >= 0)*/ {
+            char c = child[i];
+            if (c == '\\' ||
+                c == '/') {
+                // found parent path 
+                break;
+            }
+            i--;
+	}
+        
+	if (i+1 >= FILENAME_MAX 
+            || i+1 >= bufSize)
+            //|| i < 0) 
+	{
+            return -1;
+	}
+	
+        memcpy(parent, child, i);
+        parent[i] = 0;
+        return 0;
+    }
+
+    
+
+    bool directoryexists(const char * path)
+    {
+        bool
+            rv = false;
+
+	DIR
+            * d = NULL;
+
+        Cpt_EINTR_RETRY_PTR(d, opendir(path));
+
+	if (d) {
+            Cpt_EINTR_RETRY_SP( closedir(d) );
+            rv = true;
+	} 
+    
+        return rv;
+    }
+
+
+    /**
+     * This class can be used in two distinct modes:
+     *
+     *  (a) removes everything, including the directory where
+     *      the traversal was started (default constructor)
+     *
+     *  (b) removes only stuff under the start directory (constructor
+     *      with path argument to start directory).
+     */
+    class Remover : public IFileVisitor
+    {
+        int              success_;
+        std::string      start_;
+    public:
+
+        Remover()
+            : success_(0)
+        {
+            ;
+        }
+
+
+        Remover(const char * start)
+            : success_(0),
+              start_(start)
+        {
+            ;
+        }
+
+
+        int success() const
+        {
+            return success_;
+        }
+
+
+        virtual bool visitFile(const char * path)
+        {
+            // 'remove' works for files and directories
+            Cpt_EINTR_RETRY(success_,remove(path));
+
+            return success_ == 0;
+        }
+
+
+        virtual DirVisitResult visitDirPre(const char * /*path*/)
+        {
+            return IFV_CONTINUE;
+        }
+
+
+        virtual bool visitDirPost(const char * path)
+        {
+            bool
+                rv = true;
+
+            if (start_.length() == 0
+                || start_ != path)
+                {
+                    rv = visitFile(path);
+                }
+
+            return rv;
+        }
+        
+    };
+
+
+
+    int removeall(const char * path)
+    {
+        // this instance will remove anything
+        Remover
+            remover;
+
+        traverse(path,
+                 &remover);
+
+        return remover.success();
+    }
+
+
+    int removeunder(const char * path)
+    {
+        // this instance will remove everything except the thing with
+        // path 'path', which happens to be the directory where the
+        // traversal starts
+        Remover
+            remover(path);
+
+        traverse(path,
+                 &remover);
+
+        return remover.success();
+    }
+
+
+    
+    int mkdirs(const char* path, int mod)
+    {
+        if (directoryexists(path))
+            {
+                return 0;
+            }
+
+        char 
+            parent[FILENAME_MAX];
+
+        if (getparent(parent, sizeof(parent), path) >= 0) {
+            // make the parent
+            mkdirs(parent, mod); 
+        } 
+        
+        return mkdir(path, mod);
+    }
+
+
+
+    int touch(const char * path,
+              int          mod)
+    {
+        int
+            fd;
+
+        Cpt_EINTR_RETRY(fd,
+                        open(path,
+                             O_WRONLY | O_CREAT | O_TRUNC,
+                             mod));
+        if (fd != -1)
+            {
+
+                Cpt_EINTR_RETRY_SP( close(fd) );
+            }
+
+        return fd == -1 ? -1 : 0;
+    }
+
+
+
+    bool isreadable(const char * path)
+    {
+        int
+            fd;
+        Cpt_EINTR_RETRY(fd,
+                        open(path,
+                             O_RDONLY));
+        bool
+            rv = (fd != -1);
+        
+        if (rv)
+            {
+            Cpt_EINTR_RETRY_SP( close(fd) );
+            }
+
+        return rv;
+    }
+
+
+
+    bool isfile(const char * path)
+    {
+        bool
+            rv = false;
+
+        struct stat 
+            buf;
+
+        int
+            res = lstat(path,
+                        &buf);
+
+        if (res == 0)
+            {
+                rv = static_cast<bool>(S_ISREG(buf.st_mode));
+            }
+
+        return rv;
+    }
+
+
+
+    off_t filesize(const char * path)
+    {
+        off_t
+            rv = 0;
+        
+        int
+            res;
+        struct stat
+            buf;
+        
+        res = stat(path,
+                   &buf);
+        
+        if (res == 0)
+            {
+                rv = buf.st_size;
+            }
+        
+        return rv;
+    }
+
+
+
+    off_t filesize(int fileDesc)
+    {
+        off_t
+            rv = 0;
+        
+        int
+            res;
+        struct stat buf;
+        
+        res = fstat(fileDesc,
+                    &buf);
+        
+        if (res == 0)
+            {
+                rv = buf.st_size;
+            }
+        
+        return rv;
+    }
+
+
+
+    time_t filemodified(const char * path)
+    {
+        time_t
+            rv = 0;
+        
+        int
+            res;
+        struct stat buf;
+        
+        res = stat(path,
+                   &buf);
+        
+        if (res == 0)
+            {
+                rv = buf.st_mtime;
+            }
+        
+        return rv;
+    }
+
+    bool fgetline(FILE* file, std::string& line)
+   	{
+		std::ostringstream buf; 
+    	while (!feof(file))
+    	{
+    		int c = fgetc(file);
+    		if (c == EOF || c == '\n') {
+				break;
+    		}
+    		buf<<(char)c; 
+    	}
+    	line = buf.str(); 
+		return !feof(file);
+   	}
+
+    int copyFile(const char * dstPath,
+                 const char * srcPath)
+    {
+        int
+            rv = CPT_CPF_OK;
+
+        ssize_t
+            res;
+        int
+            dstFD;
+        Cpt_EINTR_RETRY(dstFD,open(dstPath,
+                                   O_WRONLY | O_TRUNC | O_CREAT,
+                                   0666));
+        if (dstFD == -1)
+            {
+                rv = CPT_CPF_DST_OPEN_ERROR;
+                return rv;
+            }
+            
+        int
+            srcFD;
+        Cpt_EINTR_RETRY(srcFD,open(srcPath,
+                                   O_RDONLY));
+        if (srcFD == -1)
+            {
+                Cpt_EINTR_RETRY(res,close(dstFD));
+
+                rv = CPT_CPF_SRC_OPEN_ERROR;
+                return rv;
+            }
+
+        char
+            buffer[256];
+        ssize_t
+            readC = 0;
+        while (true)
+            {
+                Cpt_EINTR_RETRY(readC,read(srcFD, 
+                                           buffer, 
+                                           sizeof(buffer)
+                                           /sizeof(char)));
+                if (readC == -1)
+                    {
+                        rv = CPT_CPF_SRC_READ_ERROR;
+                        break;
+                    }
+                else if (readC == 0)
+                    {
+                        // end of file
+                        break;
+                    }
+                else
+                    {
+                        ssize_t
+                            writtenC = 0;
+
+                        while (writtenC < readC)
+                            {
+                                Cpt_EINTR_RETRY(res,write(dstFD,
+                                                          buffer + writtenC,
+                                                          readC - writtenC));
+                                if (res == -1)
+                                    {
+                                        rv = CPT_CPF_DST_WRITE_ERROR;
+                                        break;
+                                    }
+                                else
+                                    {
+                                        writtenC += res;
+                                    }
+                            }
+                    }
+            }
+
+        Cpt_EINTR_RETRY(res,close(srcFD));
+        Cpt_EINTR_RETRY(res,close(dstFD));
+
+        return rv;
+    }
+
+
+
+    /**
+     * A file visitor that can copy files and directories.
+     */
+    class Copier : public IFileVisitor
+    {
+        int          result_;
+        bool         inclusive_;
+        
+        std::string  srcBasePath_;
+        std::string  dstBasePath_;
+
+    public:
+        Copier(const char * dstPath,
+               const char * srcPath,
+               bool         inclusive)
+            : result_(CPT_CP_INVALID_ARG_ERROR),
+              inclusive_(inclusive)
+        {
+            // NOTE: result_ is initialized to invalid argument error
+
+            size_t
+                pathSize = std::max(strlen(dstPath),
+                                      strlen(srcPath)) + 1;
+            auto_array<char>
+                parentPath(new char[pathSize]);
+
+            if (isfile(srcPath) && isreadable(srcPath))
+                {
+                    int
+                        result = getparent(parentPath.get(),
+                                           pathSize,
+                                           srcPath);
+                    
+                    if (result == 0)
+                        {
+                            srcBasePath_ = parentPath.get();
+                            
+                            if (isfile(dstPath) && isreadable(srcPath))
+                                {
+                                    result = getparent(parentPath.get(),
+                                                       pathSize,
+                                                       dstPath);
+                                    if (result == 0)
+                                        {
+                                            dstBasePath_ = parentPath.get();
+                                            result_ = CPT_CP_OK;
+                                        }
+                                }
+                            else
+                                {
+                                    dstBasePath_ = dstPath;
+                                    result_ = CPT_CP_OK;
+                                }
+                        }
+                }
+            else if (directoryexists(srcPath))
+                {
+                    if (inclusive)
+                        {
+                            // If inclusiveness is required, then the
+                            // src base path must be the parent path
+                            // of the src path given here, so that the
+                            // src directory gets explicitly copied
+                            // too to dst.
+                            //
+                            // NOTE: siblings of src dir do not get
+                            // copied, since traversal starts at
+                            // srcPath, it's just what we set as base.
+                            int
+                                result = getparent(parentPath.get(),
+                                                   pathSize,
+                                                   srcPath);
+                            if (result == 0)
+                                {
+                                    srcBasePath_ = parentPath.get();
+                                }
+                            else
+                                {
+                                    // must not proceed
+                                    return;
+                                }
+                        }
+                    else
+                        {
+                            // exclusive 
+                            srcBasePath_ = srcPath;
+                        }
+
+                    if (!isfile(dstPath))
+                        {
+                            dstBasePath_ = dstPath;
+                            result_ = CPT_CP_OK;
+                        }
+                    // else: insensible input: copying dir to file
+                }
+        }
+
+
+        /**
+         * Whether to copy the src directory itself to dst (inclusive)
+         * or only its contents (exclusive).
+         */
+        void setInclusive(bool inclusive)
+        {
+            inclusive_ = inclusive;
+        }
+
+
+        int result() const
+        {
+            return result_;
+        }
+
+
+        virtual bool visitFile(const char * path)
+        {
+            std::string
+                file(getDst(path));
+
+            result_ = copyFile(file.c_str(),
+                               path);
+
+            return result_ == CPT_CP_OK;
+        }
+
+
+        virtual DirVisitResult visitDirPre(const char * path)
+        {
+            std::string
+                dir(getDst(path));
+
+            int
+                result = mkdirs(dir.c_str(),
+                                0666);
+            if (result != 0)
+                {
+                    result_ = CPT_CP_DIR_CREATE_ERROR;
+                }
+
+            return result_ == CPT_CP_OK ? IFV_CONTINUE : IFV_STOPTRAVERSAL;
+        }
+
+
+        virtual bool visitDirPost(const char * /* path */)
+        {
+            return result_ == CPT_CP_OK;
+        }
+
+    private:
+
+        /**
+         * path must be a child-or-same as srcPath given to
+         * constructor. This method computes the destination path that
+         * corresponds to the path argument - taking into account
+         * srcBasePath_ and dstBasePath_.
+         */
+        std::string getDst(const char * path)
+        {
+            using namespace std;
+
+            string
+                diff(path + srcBasePath_.length());
+            if (diff[0] == '\\' || diff[0] == '/')
+                {
+                    diff = diff.substr(1);
+                }
+
+            string
+                rv(dstBasePath_);
+            if (rv[rv.length() - 1] != '\\'
+                && rv[rv.length() - 1] != '/')
+                {
+                    rv += Cpt_PATH_SEPARATOR;
+                }
+            rv += diff;
+
+            return rv;
+        }
+    };
+
+
+
+    int copy(const char * dstPath,
+             const char * srcPath,
+             bool         includeSrcDir)
+    {
+        Copier
+            copier(dstPath,
+                   srcPath,
+                   includeSrcDir);
+
+        if (copier.result() == CPT_CP_OK)
+            {
+                traverse(srcPath,
+                         &copier);
+            }
+
+        return copier.result();
+    }
+
+
+
+    IFileVisitor::~IFileVisitor()
+    {
+        ;
+    }
+
+
+    DIRSentry::DIRSentry(DIR * d)
+        : d_(d)
+    {
+        ;
+    }
+
+
+    DIRSentry::~DIRSentry()
+    {
+        Cpt_EINTR_RETRY_SP( closedir(d_) );
+    }
+
+
+
+    bool traverse_(const char   * path,
+                   IFileVisitor * visitor)
+    {
+        bool
+            goOn = true;
+
+        DIR
+            * d;
+        Cpt_EINTR_RETRY_PTR(d, opendir(path));
+        
+        dirent
+            * dir;
+
+        if (d != NULL)
+            {
+                {
+                    DIRSentry
+                        dirSentry(d);
+
+                    IFileVisitor::DirVisitResult
+                        dirVisitResult = visitor->visitDirPre(path);
+
+                    goOn = dirVisitResult != IFileVisitor::IFV_STOPTRAVERSAL;
+
+                    while (dirVisitResult == IFileVisitor::IFV_CONTINUE 
+                           && goOn)
+                        {
+                            Cpt_EINTR_RETRY_PTR(dir, readdir(d));
+
+                            if (dir == NULL)
+                                break;
+
+                            // TODO on true POSIX, you may get back
+                            // the current and parent directory as
+                            // well ... in that case, use the code below.
+                            // 
+                            // if (strcmp(".", dir->d_name) == 0 ||
+                            // strcmp("..", dir->d_name) == 0)
+                            // continue;
+
+                            std::string
+                                child(path);
+                            if (child[child.size() - 1] != DIR_SEPARATOR)
+                                {
+                                    child += DIR_SEPARATOR;
+                                }
+                            child += dir->d_name;
+                        
+                            goOn = traverse_(child.c_str(),
+                                             visitor);
+                        }
+                    // no need to call closedir - done by dirSentry
+                }
+
+                if (goOn)
+                    {
+                        goOn = visitor->visitDirPost(path);
+                    }
+            }
+        else
+            {
+                goOn = visitor->visitFile(path);
+            }
+
+        return goOn;
+    }
+
+
+
+    void traverse(const char   * path,
+                  IFileVisitor * visitor)
+    {
+        traverse_(path,
+                  visitor);
+    }
+
+
+
+    void pathappend(std::string & path,
+                    const char  * fragment)
+    {
+        // TODO platform specific
+        if (path[path.length()-1] != '\\')
+            {
+                path += '\\';
+            }
+        path += fragment;
+    }
+
+
+
+    FileDescSentry::FileDescSentry(int * fd)
+        : fileDesc_(fd)
+    {
+        ;
+    }
+    
+    
+    void FileDescSentry::release()
+    {
+        fileDesc_ = NULL;
+    }
+    
+    
+    FileDescSentry::~FileDescSentry()
+    {
+        if (fileDesc_ != NULL
+            && *fileDesc_ != -1)
+            {
+                Cpt_EINTR_RETRY_SP( close(*fileDesc_) );
+            }
+    }
+    
+    
+    FileSentry::FileSentry(FILE * file)
+    : file_( file )
+    {
+		;
+    }
+	
+	
+	void FileSentry::release()
+	{
+		file_ = NULL; 
+	}
+
+	FileSentry::~FileSentry()
+	{
+		if ( file_ != NULL )
+		{
+			Cpt_EINTR_RETRY_SP( fclose(file_) ); 
+		}
+	}
+
+
+}