/*
 * Copyright (C) 2009 - 2010 Funambol, Inc.
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License version 3 as published by
 * the Free Software Foundation with the addition of the following permission
 * added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED
 * WORK IN WHICH THE COPYRIGHT IS OWNED BY FUNAMBOL, FUNAMBOL DISCLAIMS THE
 * WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
 *
 * This program 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 General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, see http://www.gnu.org/licenses or write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301 USA.
 *
 * You can contact Funambol, Inc. headquarters at 643 Bair Island Road, Suite
 * 305, Redwood City, CA 94063, USA, or at email address info@funambol.com.
 *
 * The interactive user interfaces in modified source and object code versions
 * of this program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU Affero General Public License version 3.
 *
 * In accordance with Section 7(b) of the GNU Affero General Public License
 * version 3, these Appropriate Legal Notices must retain the display of the
 * "Powered by Funambol" logo. If the display of the logo is not reasonably
 * feasible for technical reasons, the Appropriate Legal Notices must display
 * the words "Powered by Funambol".
 */

/* $Id$ */

#include "FileSystemUtils.h"

#include <string>
#include <dirent.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>


namespace NS_DM_Client
{

const char c_pathSeparator = '/';
const char* const c_pathSeparatorStr = "/";

const mode_t c_fullAccessMode = S_IRWXU | S_IRWXG | S_IRWXO; // 0777
const mode_t c_fullAccessModeExceptExec = (S_IRWXU & ~ S_IXUSR) | (S_IRWXG & ~S_IXGRP) | (S_IRWXO & ~S_IXOTH); 
const mode_t c_accessMode = c_fullAccessModeExceptExec;//c_fullAccessMode;


//------------------------------------------------------------------------------------------------------
// need sync outside
bool is_entry_dir(const char* path)
{
    bool res = false;
    struct stat st;
    if (lstat(path, &st) == 0)
    {
        if (S_ISDIR(st.st_mode))
        {
            if (!(path[strlen(path)-1] == '.'))
            {
                res = true;
            }
        }
    }
    return res;
}

//------------------------------------------------------------------------------------------------------

bool is_entry_file(const char* path)
{
    bool res = false;
    struct stat st;
    if (lstat(path, &st) == 0)
    {
        if (S_ISREG(st.st_mode))
        {
            res = true;
        }
    }
    return res;
}

//------------------------------------------------------------------------------------------------------

bool DeleteDirectoryByPath(const String& path)
{
    bool res = false;
    DIR* dir_handle = opendir(path.c_str());
    if (dir_handle)
    {
        struct dirent* entry_info;
        String entry_path;
        while ( (entry_info = readdir(dir_handle)) != 0 )
        {
            entry_path = path + entry_info->d_name;
            if (is_entry_file(entry_path.c_str()))
            {
                unlink(entry_path.c_str());
            }
            else if (is_entry_dir(entry_path.c_str()))
            {
                if (entry_path[entry_path.length()-1] != '/')
                {
                    entry_path = entry_path + '/';
                }
                res = DeleteDirectoryByPath(entry_path);
            }
        }
        closedir(dir_handle);
        if (rmdir(path.c_str()) == 0)
        {
            res = true;
        }
    }
    return res;
}

//------------------------------------------------------------------------------------------------------

bool DeleteFilesystemEntity(const String& path)
{
    bool res = false;
    // try delete as private data
    String entity = path + ".priv";
    if (unlink(entity.c_str()) != 0)
    {
        // if failed, try delete as directory
        String full_path = path;
        if (full_path[full_path.length()-1] != '/')
        {
            full_path = full_path + '/';
        }
        res = DeleteDirectoryByPath(full_path);
    }
    else
    {
        res = true;
        rmdir(path.c_str());
    }
    return res;
}

//------------------------------------------------------------------------------------------------------

bool CreatePath(const char* path)
{
    bool res = true;

    size_t pos_beg = 0;
    size_t pos_end = 0;

    String full_path = path;
    if (full_path[full_path.length()-1] != c_pathSeparator)
    {
        full_path = full_path + c_pathSeparatorStr;
    }

    String FormedPath;

    mode_t fumask = 0777 - (c_fullAccessMode & 0777);
    umask(fumask);
    mode_t mode = c_fullAccessMode | 0777;

    int status;
    bool first_separator = true;
    while ( (pos_end = full_path.find(c_pathSeparator, pos_beg)) != String::npos )
    {
        if (first_separator)
        {
            first_separator = false;
            pos_beg = pos_end + 1;
            continue;
        }

        FormedPath = full_path.substr(0, pos_end + 1);

        status = mkdir(FormedPath.c_str(), mode);
        if ( ! ((status == 0) || ((status == -1) && (errno == EEXIST)))  )
        {
            res = false;
            break;
        }
        pos_beg = pos_end + 1;
    }

    umask(0);
    return res;
}

}
