/*Copyright 2010-2011, Loïc BARTOLETTI. All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are
permitted provided that the following conditions are met:

   1. Redistributions of source code must retain the above copyright notice, this list of
      conditions and the following disclaimer.

   2. Redistributions in binary form must reproduce the above copyright notice, this list
      of conditions and the following disclaimer in the documentation and/or other materials
      provided with the distribution.

THIS SOFTWARE IS PROVIDED BY Loïc BARTOLETTI ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Loïc BARTOLETTI OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

The views and conclusions contained in the software and documentation are those of the
authors and should not be interpreted as representing official policies, either expressed
or implied, of Loïc BARTOLETTI.
http://coder.tuxfamily.org/
*/

/**
 * \file zipzap.c
 * \brief Programme de (de)zippage pour la démonstration de libzip.
 * \author Loïc Bartoletti
 * \version 0.1
 * \date 05 janvier 2011
 *
 * Ce programme n'est qu'une simple démonstration des fonctionnalités de base de la libzip concernant les archives... zip.
 * Il ne se veut pas remplacer d'autres programmes qui font très bien leurs travails (7z & co).
 * Il est compatible avec les systèmes unix/posix. Une version windows peut être facilement réalisée.
 *
 */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#if defined(__POSIX_VISIBLE) || defined(_POSIX_C_SOURCE)
#include <unistd.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#else
/* TODO : pour windows inclure les en-têtes spécifiques */
#error "La source n'est pas encore disponible pour les systèmes non Unix/Posix."
#endif

#define FREE(x) do { free(x); x = NULL; } while (0)

/* l'en-tête de la libzip */
#include <zip.h>

/* retour des fonctions propres à ZipZap */
#define ZIPZAP_SUCCESS 1
#define ZIPZAP_FAILURE -1

/* mode de création de l'archive zip */
#define ADD 1 /* ajoute des fichiers dans l'archives si elle existe déjà */
#define CREATE 2 /* créer l'archive. Si elle existe déjà elle sera supprimé */
#define EXIST 3 /* créer l'archive que si elle n'existe pas */

/* mode pour le remplacement de fichier dans l'archive */
#define REPLACE_NOT_ADD 0 /* remplace mais n'ajoute pas si le fichier n'existe pas */
#define REPLACE_ADD 1 /* remplace et ajoute si le fichier n'existe pas */


static char buf_erreur[256];

static int afficherFichierZip(const char* fichierZip);
static int effacerFichierZip(const char* fichierZip, const char* fichier);
static int renommerFichierZip(const char* fichierZip, const char* fichierFrom, const char* fichierTo);
static int creerFichierZip(const char* fichierZipEnSortie, int modeZip, int argc, char *arg[]);
static int decompresserFichierZip(const char* fichierZip, const char* repSortie, const char* motDePasse);
static int ajouteDossier(const char *dir, struct zip *f_zip);
static int remplacerFichierZip(const char* fichierZip, const char* fichier, int ajout);
static int extraireFichierZip(const char* fichierZip, const char* fichier, const char* repSortie, const char* motDePasse);
static int extraireFichier(int id, struct zip *f_zip, const char *repSortie, const char* motDePasse);
static int verifPresenceFichier(struct zip *f_zip, const char* fichier);
static void usage(char *soft);


/* http://fr.w3support.net/index.php?db=so&id=675039 */
/*
@(#)File:           $RCSfile: mkpath.c,v $
@(#)Version:        $Revision: 1.12 $
@(#)Last changed:   $Date: 2008/05/19 00:43:33 $
@(#)Purpose:        Create all directories in path
@(#)Author:         J Leffler
@(#)Copyright:      (C) JLSS 1990-91,1997-98,2001,2005,2008
@(#)Product:        :PRODUCT:
*/
int mkpath(const char *path, mode_t mode);
static int do_mkdir(const char *path, mode_t mode);


/**
 * \fn static void usage(char *soft)
 * \brief Le fameux "Usage" si l'utilisateur n'a pas ce qu'il fallait.
 *
 * \param soft Nom du logiciel (argv[0]).
 *
 */
static void usage(char *soft)
{
    printf("Afficher les fichiers de l'archive \"zip\".\n\tUsage : %s -t <zip>\n", soft);
    printf("Effacer le fichier de l'archive \"zip\".\n\tUsage : %s -del <zip> <fichier>\n", soft);
    printf("Renommer le fichier \"fichier from\" en \"fichier to\" de l'archive \"zip\".\n\tUsage : %s -ren <zip> <fichier from> <fichier to>\n", soft);
    printf("Remplacer \"fichier\" dans l'archive \"zip\".\n\tUsage : %s <-ra : ajoute s'il n'existe pas/-re : remplace seulement> <zip> <fichier>\n", soft);
    printf("Extraire \"fichier\" de l'archive \"zip\"  (dans \"répertoire de sortie\") (-p avec le mot de passe).\n\tUsage : %s -ex <zip> <fichier> (-o <répertoire de sortie>) (-p <mot de passe>)\n", soft);
    printf("Décompresser l'archive \"zip\" (dans \"répertoire de sortie\") (-p avec le mot de passe).\n\tUsage : %s -d <zip> (-o <répertoire de sortie>) (-p <mot de passe>)\n", soft);
    printf("Compresser les fichiers... dans l'archive \"zip\".\n\tUsage : %s <mode> <zip> <fichiers...>\n", soft);
    printf("mode :\n" \
           "\t-a : ADD : ajoute les fichiers à l'archive.\n" \
           "\t-c : CREATE : créer une nouvelle archive. Si une archive existe déjà elle sera supprimée\n" \
           "\t-e : EXIST : créer une nouvelle archive. Si une archive existe déjà rien ne sera effectué\n");
}

/**
 * \fn int main (void)
 * \brief Entrée du programme.
 *
 * \return EXIT_SUCCESS - Arrêt normal du programme.
 */
int main(int argc, char *argv[])
{

    if(argc<2)
        usage(argv[0]);
    else
    {

        /* affiche les fichiers */
        if(strncmp("-t",argv[1], strlen(argv[1])*sizeof(char))==0)
        {
            if(argc==3)
                afficherFichierZip(argv[2]);
            else
                usage(argv[0]);
        }
        /* décompresse les fichiers */
        else if(strncmp("-d",argv[1],strlen(argv[1])*sizeof(char))==0)
        {
            if (argc==3)
                decompresserFichierZip(argv[2], NULL, NULL);
            else if( (argc==5) && (strncmp("-p",argv[3],strlen(argv[3])*sizeof(char))==0) )
                decompresserFichierZip(argv[2], NULL, argv[4]);
            else if( (argc == 5) && (strncmp("-o",argv[3],strlen(argv[3])*sizeof(char))==0))
                decompresserFichierZip(argv[2], argv[4], NULL);
            else if( (argc == 7) && (strncmp("-o",argv[3],strlen(argv[3])*sizeof(char))==0) && (strncmp("-p",argv[5],strlen(argv[5])*sizeof(char))==0))
                decompresserFichierZip(argv[2], argv[4], argv[6]);
            else
                usage(argv[0]);
        }

        /* compresse les fichiers */
        else if(strncmp(argv[1], "-a", strlen(argv[1])*sizeof(char))==0)
        {
            if (argc>=3)
                creerFichierZip(argv[2], ADD, argc, argv);
            else
                usage(argv[0]);
        }
        else if(strncmp(argv[1], "-c", strlen(argv[1])*sizeof(char))==0)
        {
            if (argc>=3)
                creerFichierZip(argv[2], CREATE, argc, argv);
            else
                usage(argv[0]);
        }
        else if(strncmp(argv[1], "-e", strlen(argv[1])*sizeof(char))==0)
        {
            if (argc>=3)
                creerFichierZip(argv[2], EXIST, argc, argv);
            else
                usage(argv[0]);
        }

        /* remplace/ajoute les fichiers */
        else if(strncmp("-ra",argv[1],strlen(argv[1])*sizeof(char))==0)
        {
            if(argc==4)
                remplacerFichierZip(argv[2], argv[3], REPLACE_ADD);
            else
                usage(argv[0]);
        }
        else if(strncmp("-re",argv[1],strlen(argv[1])*sizeof(char))==0)
        {

            if(argc==4)
                remplacerFichierZip(argv[2], argv[3], REPLACE_NOT_ADD);
            else
                usage(argv[0]);
        }

        /*extrait les fichiers */
        else if(strncmp(argv[1],"-ex",strlen(argv[1])*sizeof(char))==0)
        {
            if(argc==4)
                extraireFichierZip(argv[2], argv[3], NULL, NULL);
            else if( (argc==6) && ((strncmp(argv[4],"-o",strlen(argv[4])*sizeof(char))==0)) )
                extraireFichierZip(argv[2], argv[3], argv[5], NULL);
            else if( (argc==6) && ((strncmp(argv[4],"-p",strlen(argv[4])*sizeof(char))==0)) )
                extraireFichierZip(argv[2], argv[3], NULL, argv[5]);
            else if( (argc==8) && ((strncmp(argv[4],"-o",strlen(argv[4])*sizeof(char))==0)) && ((strncmp(argv[6],"-p",strlen(argv[6])*sizeof(char))==0)))
                extraireFichierZip(argv[2], argv[3], argv[5], argv[7]);
            else
                usage(argv[0]);
        }

        /* efface le fichier */
        else if(strncmp("-del",argv[1],strlen(argv[1])*sizeof(char))==0)
        {
            if(argc==4)
                effacerFichierZip(argv[2], argv[3]);
            else
                usage(argv[0]);
        }
        /* renomme le fichier */
        else if(strncmp("-ren",argv[1],strlen(argv[1])*sizeof(char))==0)
        {
            if(argc==5)
                renommerFichierZip(argv[2], argv[3], argv[4]);
            else
                usage(argv[0]);
        }

        else
            usage(argv[0]);
    }

    return EXIT_SUCCESS;

}


/**
 * \fn static int afficherFichierZip(const char* fichierZip)
 * \brief Affiche les fichiers à l'intérieur de l'archive Zip.
 *
 * \return ZIPZAP_SUCCESS : Retour OK ; ZIPZAP_FAILURE : Retour d'erreur.
 */
static int afficherFichierZip(const char* fichierZip)
{

    if(fichierZip == NULL)
        return ZIPZAP_FAILURE;

    int err = 0;
    struct zip *f_zip=NULL;

    f_zip = zip_open(fichierZip, ZIP_CHECKCONS, &err); /* on ouvre l'archive zip */

    /* s'il y a des erreurs */
    if(err != ZIP_ER_OK)
    {
        zip_error_to_str(buf_erreur, sizeof buf_erreur, err, errno);
        printf("Error %d : %s\n",err, buf_erreur);
        return ZIPZAP_FAILURE;
    }

    /* si le fichier zip n'est pas ouvert */
    if(f_zip==NULL)
    {
        printf("Erreur à l'ouverture du fichier %s\n", fichierZip);
        return ZIPZAP_FAILURE;
    }

    /* on récupère le nombre de fichier dans l'archive zip */
    int count = zip_get_num_files(f_zip);
    if(count==-1)
    {

        printf("Erreur à la lecture du fichier %s\n", fichierZip);
        zip_close(f_zip);
        f_zip = NULL;
        return ZIPZAP_FAILURE;
    }

    int i = 0;
    printf("Nombre de fichiers dans l'archive : %d\n",count);

    for(i=0; i<count; i++)
    {
        /* on utilise la position "i" pour récupérer le nom des fichiers */
        printf("%s\n", zip_get_name(f_zip, i, ZIP_FL_UNCHANGED));
    }

    zip_close(f_zip);
    f_zip = NULL;

    return ZIPZAP_SUCCESS;

}


/**
 * \fn static int decompresserFichierZip(const char* fichierZip, const char* repSortie)
 * \brief Décompresse l'archive zip "fichierZip" dans le repertoire "repSortie".
 *
 * \param fichierZip Le nom de l'archive zip à décompresser.
 * \param repSortie Le répertoire où doit être décompressée l'archive. Si repSortie vaut NULL, le répertoire est l'endroit d'où est lancée la commande.
 * \param motdePasse Le mot de passe de l'archive protégée.
 *
 * \return ZIPZAP_SUCCESS : Retour OK ; ZIPZAP_FAILURE : Retour d'erreur.
 */
static int decompresserFichierZip(const char* fichierZip, const char* repSortie, const char* motDePasse)
{

    /* Code d'origine : */
    /* http://www.siteduzero.com/forum-83-372372-p1-c-zip-et-unzip.html#r3519929 */
    /* http://forum.ubuntu-fr.org/viewtopic.php?pid=2596893#p2596893 Visité le 02/01/2011 */
    /* modifié pour ajouter la gestion des erreurs et quelques fonctionnalités */

    int err=0;
    struct zip *f_zip=NULL;


    /* 1. Ouverture de l'archive */
    f_zip = zip_open(fichierZip, ZIP_CHECKCONS, &err);
    /* s'il y a des erreurs */
    if(err != ZIP_ER_OK)
    {
        zip_error_to_str(buf_erreur, sizeof buf_erreur, err, errno);
        printf("Error %d : %s\n",err, buf_erreur);
        return ZIPZAP_FAILURE;
    }
    /* si le fichier zip n'est pas ouvert */
    if(f_zip==NULL)
    {
        printf("Erreur à l'ouverture du fichier %s\n", fichierZip);
        return ZIPZAP_FAILURE;
    }


    /* 2. on récupère le nombre de fichier dans l'archive zip */
    int count = zip_get_num_files(f_zip);
    if(count==-1)
    {
        printf("Erreur à l'ouverture du fichier %s\n", fichierZip);
        zip_close(f_zip);
        f_zip = NULL;
        return ZIPZAP_FAILURE;
    }

    printf("Nombre de fichiers dans l'archive : %d\n", count);

    int i;

    /* 3. on lit tout les fichiers */
    for(i=0; i<count; i++)
    {
        /* on lance la fonction qui extraira le fichier en position "i" dans l'archive Zip */
        if(extraireFichier(i, f_zip, repSortie, motDePasse)==ZIPZAP_FAILURE)
        {
            printf("Erreur à l'extraction du fichier %s\n", zip_get_name(f_zip, i, ZIP_FL_UNCHANGED));
            zip_close(f_zip);
            f_zip = NULL;
            return ZIPZAP_FAILURE;
        }
    }

    /* lecture terminée, fermeture de l'archive */
    zip_close(f_zip);
    f_zip = NULL;


    return ZIPZAP_SUCCESS;
}

/* Ajoute les fichiers telles qu'ils sont envoyés dans la ligne de commande */
/* Pose problèmes avec les fichiers du styles "../../fichiers" */
/**
 * \fn static int creerFichierZip(const char* fichierZipEnSortie, int modeZip, int argc, char *arg[])
 * \brief Créer l'archive zip "fichierZipEnSortie" suivant le mode "modeZip" avec les fichiers contenus dans *arg[].
 *
 * \param fichierZipEnSortie Le nom de l'archive zip à créer en sortie.
 * \param modeZip Mode de création de l'archive ADD ; CREATE ou EXIST. (voir les définitions).
 * \param argc Nombre de fichiers reçus par le programme et transmis à la fonction.
 * \param argv Chaînes de caractères reçus par le programme et transmis à la fonction. Ces chaînes contiennent les fichiers/répertoires à ajouter.
 *
 * \return ZIPZAP_SUCCESS : Retour OK ; ZIPZAP_FAILURE : Retour d'erreur.
 */
static int creerFichierZip(const char* fichierZipEnSortie, int modeZip, int argc, char *arg[])
{

    struct zip *f_zip=NULL;
    struct zip_source *doc = NULL;
    int err = 0;

    /* Suivant le mode choisit pour la création de l'archive on définit les flags */
    if(modeZip==CREATE)
    {
        /* on supprime l'archive pour en créer une nouvelle */
        remove(fichierZipEnSortie);
        f_zip=zip_open(fichierZipEnSortie, ZIP_CREATE, &err); /* on crée l'archive */
    }
    else if(modeZip==EXIST)
    {
        f_zip=zip_open(fichierZipEnSortie, ZIP_EXCL|ZIP_CREATE, &err); /* on ne crée pas l'archive si elle existe, mais si elle n'existe pas on la crée */
    }
    else if(modeZip==ADD)
    {
        f_zip=zip_open(fichierZipEnSortie, ZIP_CREATE, &err); /* on crée l'archive si elle n'existe pas */
    }
    else
    {
        printf("Erreur du choix du mode\n");
        usage(arg[0]);
        return ZIPZAP_FAILURE;
    }

    /* s'il y a des erreurs */
    if(err != ZIP_ER_OK)
    {
        zip_error_to_str(buf_erreur, sizeof buf_erreur, err, errno);
        printf("Error %d : %s\n",err, buf_erreur);
        return ZIPZAP_FAILURE;
    }
    /* si le fichier zip n'est pas ouvert */
    if(f_zip==NULL)
    {
        printf("Erreur à l'ouverture du fichier %s\n", fichierZipEnSortie);
        return ZIPZAP_FAILURE;
    }


    /* on positionne i à 3 car on a dans le tableau il y a : "0. Le nom du programme" "1. Le mode de création" "2. Le nom de l'archive" */
    int i = 3;
    for(; i<argc; i++)
    {

        if(verifPresenceFichier(f_zip, arg[i])==ZIPZAP_FAILURE)
        {
            printf("Erreur lors de l'ajout du fichier/dossier \"%s\" à l'archive %s\n", arg[i], fichierZipEnSortie);
            zip_close(f_zip);
            f_zip = NULL;
            zip_source_free(doc);
            doc = NULL;
            return ZIPZAP_FAILURE;
        }

#if defined(__POSIX_VISIBLE) || defined(_POSIX_C_SOURCE)
        /* on test si le fichier demandé est un dossier ou non */
        struct stat f_stat;
        if(lstat(arg[i], &f_stat) != -1)
        {
            if(S_ISDIR(f_stat.st_mode))
            {
                /* Si cela en est un, on l'ajoute à l'archive */
                if(zip_add_dir(f_zip, arg[i]) == -1)
                {

                    printf("%s\n", zip_strerror(f_zip));
                    zip_close(f_zip);
                    f_zip = NULL;
                    zip_source_free(doc);
                    doc = NULL;

                    return ZIPZAP_FAILURE;
                }

                /* Puis on ajoute tous les fichiers du dossier et de ses sous-dossiers */
                if(ajouteDossier(arg[i], f_zip)==ZIPZAP_FAILURE)
                {
                    printf("Erreur à l'ajout du dossier %s\n", arg[i]);
                    zip_close(f_zip);
                    f_zip = NULL;
                    zip_source_free(doc);
                    doc = NULL;
                    return ZIPZAP_FAILURE;
                }

            }
            else /* Sinon on le traite comme un fichier normal */
            {

                /* que l'on recupère dans un zip_source */
                if((doc=zip_source_file(f_zip,arg[i],(off_t)0,(off_t)0))==NULL)
                {

                    printf("%s\n", zip_strerror(f_zip));
                    zip_close(f_zip);
                    f_zip = NULL;
                    zip_source_free(doc);
                    doc = NULL;
                    return ZIPZAP_FAILURE;
                }

                /* pour l'inclure dans l'archive */
                if(zip_add(f_zip, arg[i], doc)==-1)
                {

                    printf("%s\n", zip_strerror(f_zip));
                    zip_close(f_zip);
                    f_zip = NULL;
                    zip_source_free(doc);
                    doc = NULL;
                    return ZIPZAP_FAILURE;
                }


            }
        }
        else
        {
            printf("Le fichier %s n'existe pas\n", arg[i]);
            zip_close(f_zip);
            f_zip = NULL;
            zip_source_free(doc);
            doc = NULL;
            return ZIPZAP_FAILURE;
        }

#endif /* posix */
        /* TODO : la même chose pour windows */

    }


    zip_close(f_zip);
    f_zip = NULL;
    zip_source_free(doc);
    doc = NULL;

    return ZIPZAP_SUCCESS;
}


/**
 * \fn static int extraireFichier(int id, struct zip *f_zip, const char *repSortie)
 * \brief Fonction ne s'occupant exclusivement que d'extraire le fichier n°"id" de l'archive "f_zip" dans "repSortie". Fonction appelée par extraireFichierZip et decompresserFichierZip.
 *
 * \param id Position du fichier à extraire de l'archive.
 * \param f_zip Archive zip contenant le fichier à extraire.
 * \param repSortie Le répertoire où doit être extrait le fichier de l'archive. Si repSortie vaut NULL, le répertoire est l'endroit d'où est lancée la commande.
 * \param motdePasse Le mot de passe de l'archive protégée.
 *
 * \return ZIPZAP_SUCCESS : Retour OK ; ZIPZAP_FAILURE : Retour d'erreur.
 */
static int extraireFichier(int id, struct zip *f_zip, const char *repSortie, const char* motDePasse)
{

    /* Code d'origine : */
    /* http://forum.ubuntu-fr.org/viewtopic.php?pid=2596893#p2596893 Visité le 02/01/2011 */
    /* http://www.siteduzero.com/forum-83-372372-p1-c-zip-et-unzip.html#r3519929 */
    /* modifié pour ajouter la gestion des erreurs et quelques fonctionnalités */

    struct zip_stat file_stat;
    struct zip_file *file_zip=NULL;
    zip_stat_index(f_zip, id, 0, &file_stat);

    /* 4. pour connaître la taille du fichier et ainsi pouvoir le lire en entier*/
    if(zip_stat(f_zip, file_stat.name, 0, &file_stat) == -1)
    {
        printf("%s\n", zip_strerror(f_zip));
        return ZIPZAP_FAILURE;
    }

    printf("taille du fichier %s : %d \n", file_stat.name, (int)(file_stat.size*sizeof(char)+1));


    /* 5. on ouvre le fichier archivé */
    if(motDePasse==NULL)
    {
        /* sans mot de passe */
        file_zip=zip_fopen(f_zip, file_stat.name, ZIP_FL_UNCHANGED);
    }
    else
    {
        /* avec mot de passe */
        file_zip=zip_fopen_encrypted(f_zip, file_stat.name, ZIP_FL_UNCHANGED, motDePasse);
    }
    if(!file_zip)
    {
        printf("%s\n", zip_strerror(f_zip));
        return ZIPZAP_FAILURE;
    }

    char *str=NULL;
    str = malloc((size_t)(file_stat.size+1));
    memset(str, 0, (size_t)(file_stat.size+1));
    if(str == NULL)
    {
        printf("Erreur d'allocation mémoire\n");
        return ZIPZAP_FAILURE;
    }


    /* 6. on lit le fichier archivé */
    if(zip_fread(file_zip, str, (size_t)(file_stat.size)) != file_stat.size)
    {
        printf("%s\n", zip_strerror(f_zip));
        FREE(str);

        zip_fclose(file_zip);
        file_zip = NULL;
        return ZIPZAP_FAILURE;
    }


    /* 7. on l'écrit en sortie en mode binaire */
    FILE *fOut = NULL;

    if(repSortie != NULL) /* si on a indiqué un répertoire de sortie */
    {


        char *repOut= malloc(FILENAME_MAX * sizeof(char));
        if(repOut == NULL)
        {
            printf("Erreur d'allocation mémoire\n");
            FREE(str);

            zip_fclose(file_zip);
            file_zip = NULL;
            return ZIPZAP_FAILURE;
        }

        /* on test les '/' pour ne pas avoir affaire avec des "foo//bar/fichier" ou autres */
        /* TODO : ajouter le test pour windows. Un simple '\' ? */
        memset(repOut, 0, FILENAME_MAX * sizeof(char));
        if( (repSortie[strlen(repSortie)-1]=='/') && (file_stat.name[0]=='/'))
        {
            strncpy(repOut, repSortie, strlen(repSortie)-2);
            strcat(repOut, file_stat.name);
        }
        else if( (repSortie[strlen(repSortie)-1]=='/') || (file_stat.name[0]=='/'))
            sprintf(repOut, "%s%s", repSortie, file_stat.name);
        else
            sprintf(repOut, "%s/%s", repSortie, file_stat.name);


        /* Avant d'extraire le fichier il faut créer les répertoires nécessaires le cas échéant */
        mkpath(repOut, 0777);

        /* si c'est autre chose qu'un dossier on l'écrit */
        if(repOut[strlen(repOut)-1]!='/')
        {
            if((fOut = fopen(repOut, "wb"))==NULL)
            {
                printf("Erreur à la création du fichier %s\n", repOut);
                FREE(str);

                FREE(repOut);

                zip_fclose(file_zip);
                file_zip = NULL;
                return ZIPZAP_FAILURE;
            }

            /* on écrit le fichier */
            fwrite(str, sizeof(char), (size_t)file_stat.size, fOut);
            fclose(fOut);
            fOut = NULL;
        }

        zip_fclose(file_zip);
        file_zip = NULL;
        FREE(str);
        FREE(repOut);



    }
    else /* sinon on utilise le répertoire d'où est lancée la commande */
    {


        /* Avant d'extraire le fichier il faut créer les répertoires nécessaires le cas échéant */
        mkpath(file_stat.name, 0777);



        /* si c'est autre chose qu'un dossier on l'écrit */
        if(file_stat.name[strlen(file_stat.name)-1] != '/' )
        {

            if((fOut = fopen(file_stat.name, "wb"))==NULL)
            {
                printf("Erreur à la création du fichier %s\n", file_stat.name);

                zip_fclose(file_zip);
                file_zip = NULL;
                FREE(str);

                return ZIPZAP_FAILURE;

            }
            /* on écrit le fichier */
            fwrite(str, sizeof(char), (size_t)file_stat.size, fOut);

            FREE(str);
            fclose(fOut);
            fOut = NULL;
            zip_fclose(file_zip);
            file_zip = NULL;

        }
    }

    FREE(str);
    file_zip = NULL;
    return ZIPZAP_SUCCESS;
}

/**
 * \fn static int extraireFichierZip(const char* fichierZip, const char* fichier, const char* repSortie)
 * \brief Fonction préparant l'extraction du fichier de l'archive zip.
 *
 * \param fichierZip Archive zip contenant le fichier à extraire.
 * \param fichier Nom du fichier/dossier à extraire.
 * \param repSortie Le répertoire où doit être extrait le fichier de l'archive. Si repSortie vaut NULL, le répertoire est l'endroit d'où est lancée la commande.
 * \param motdePasse Le mot de passe de l'archive protégée.
 *
 * \return ZIPZAP_SUCCESS : Retour OK ; ZIPZAP_FAILURE : Retour d'erreur.
 */
static int extraireFichierZip(const char* fichierZip, const char* fichier, const char* repSortie, const char* motDePasse)
{

    int visu = 0;
    struct zip *f_zip=NULL;
    int err=0;

    f_zip=zip_open(fichierZip, ZIP_CHECKCONS, &err);
    /* s'il y a des erreurs */
    if(err != ZIP_ER_OK)
    {
        zip_error_to_str(buf_erreur, sizeof buf_erreur, err, errno);
        printf("Error %d : %s\n",err, buf_erreur);
        return ZIPZAP_FAILURE;
    }
    /* si le fichier zip n'est pas ouvert */
    if(f_zip==NULL)
    {
        printf("Erreur à l'ouverture du fichier %s\n", fichierZip);
        return ZIPZAP_FAILURE;
    }

    visu=zip_name_locate(f_zip,fichier,0);
    if (visu==-1) /* recherche de l'emplacement du fichier dans le zip */
    {
        printf("Le fichier %s n'existe pas dans %s\n", fichier, fichierZip);
        printf("Ajouter le caractère '/' à la fin du nom s'il s'agit d'un dossier\n");
        zip_close(f_zip);
        f_zip = NULL;
        return ZIPZAP_FAILURE;
    }



    /* si on demande l'extraction d'un répertoire */
    /* le dernier caractère est le symbole du répertoire '/' */
    if(fichier[strlen(fichier)-1]=='/') /* TODO : ajouter le test pour windows. Un simple '\' ? */
    {
        char *ptr = NULL;
        int i = 0;
        int count = zip_get_num_files(f_zip);
        if(count==-1)
        {
            zip_close(f_zip);
            f_zip = NULL;
            printf("Erreur à l'ouverture du fichier %s\n", fichierZip);
            return ZIPZAP_FAILURE;
        }
        for(i=0; i<count; i++)
        {


            if( (ptr=strstr(zip_get_name(f_zip, i, ZIP_FL_UNCHANGED), fichier)) != NULL)
            {
                /* si le fichier rencontré dans l'archive et le dossier lui même, on ne l'extrait pas */
                if( (strlen(fichier) == strlen(ptr)) && (strcmp(ptr,fichier)==0))
                {
                    printf("Extraction des fichiers du dossier %s\n",ptr);
                }
                else /* si ce sont ces fichiers, oui */
                {

                    if(extraireFichier(i, f_zip, repSortie, motDePasse)==ZIPZAP_FAILURE)
                    {

                        printf("Erreur à l'extraction du fichier %s\n", zip_get_name(f_zip, i, ZIP_FL_UNCHANGED));
                        zip_close(f_zip);
                        f_zip = NULL;
                        ptr = NULL;
                        return ZIPZAP_FAILURE;
                    }

                }

            }
        }
        ptr = NULL;
    }
    else
    {



        if(extraireFichier(visu, f_zip, repSortie, motDePasse)==ZIPZAP_FAILURE)
        {
            printf("Erreur à l'extraction du fichier %s\n", zip_get_name(f_zip, visu, ZIP_FL_UNCHANGED));
            zip_close(f_zip);
            f_zip = NULL;

            return ZIPZAP_FAILURE;
        }

    }

    zip_close(f_zip);

    return ZIPZAP_SUCCESS;
}

/**
 * \fn static int effacerFichierZip(const char* fichierZip, const char* fichier)
 * \brief Efface le fichier/dossier "fichier" de l'archive zip "fichierZip".
 *
 * \param fichierZip Archive zip contenant le fichier à effacer.
 * \param fichier Nom du fichier/dossier à effacer.
 *
 * \return ZIPZAP_SUCCESS : Retour OK ; ZIPZAP_FAILURE : Retour d'erreur.
 */
static int effacerFichierZip(const char* fichierZip, const char* fichier)
{
    int visu = 0;
    struct zip * f_zip=NULL;
    int err = 0;

    f_zip=zip_open(fichierZip,ZIP_CREATE,&err);
    /* s'il y a des erreurs */
    if(err != ZIP_ER_OK)
    {
        zip_error_to_str(buf_erreur, sizeof buf_erreur, err, errno);
        printf("Error %d : %s\n",err, buf_erreur);
        return ZIPZAP_FAILURE;
    }
    /* si le fichier zip n'est pas ouvert */
    if(f_zip==NULL)
    {
        printf("Erreur à l'ouverture du fichier %s\n", fichierZip);
        return ZIPZAP_FAILURE;
    }

    visu=zip_name_locate(f_zip,fichier,0);
    if (visu==-1) /* recherche de l'emplacement du fichier dans le zip */
    {
        printf("Le fichier %s n'existe pas dans %s\n", fichier, fichierZip);
        zip_close(f_zip);
        f_zip = NULL;
        return ZIPZAP_FAILURE;

    }

    /* si on demande la suppression d'un répertoire */
    if(fichier[strlen(fichier)-1]=='/')
    {
        char *ptr = NULL;
        int i = 0;
        int count = zip_get_num_files(f_zip);
        if(count==-1)
        {
            printf("Erreur à l'ouverture du fichier %s\n", fichierZip);
            zip_close(f_zip);
            f_zip = NULL;
            ptr = NULL;
            return ZIPZAP_FAILURE;
        }

        for(i=0; i<count; i++)
        {


            /* on parcours tous les fichiers du zip pour savoir si un fichier est dans le dossier à supprimer */
            if( (ptr=strstr(zip_get_name(f_zip, i, ZIP_FL_UNCHANGED), fichier)) != NULL)
            {
                /* on efface le fichier positionné à l'index i */
                if(zip_delete(f_zip,i) == -1)
                {
                    printf("%s\n", zip_strerror(f_zip));
                    zip_close(f_zip);
                    f_zip = NULL;
                    ptr = NULL;
                    return ZIPZAP_FAILURE;
                }
                printf("Le fichier %s a été supprimé dans %s\n", zip_get_name(f_zip, i, ZIP_FL_UNCHANGED), fichierZip);

            }
        }
        ptr = NULL;
    }
    else
    {
        /* sinon on supprime simplement le fichier trouvé par zip_name_locate à la position visu */
        if(zip_delete(f_zip,visu) == -1)
        {
            printf("%s\n", zip_strerror(f_zip));
            zip_close(f_zip);
            f_zip = NULL;

            return ZIPZAP_FAILURE;
        }
        printf("Le fichier %s a été supprimé dans %s\n", fichier, fichierZip);
    }


    /* lecture terminée, fermeture de l'archive */
    zip_close(f_zip);
    f_zip = NULL;

    return ZIPZAP_SUCCESS;
}

/**
 * \fn static int renommerFichierZip(const char* fichierZip, const char* fichierFrom, const char* fichierTo)
 * \brief Efface le fichier/dossier "fichierFrom" en "FichierTo" de l'archive zip "fichierZip".
 *
 * \param fichierZip Archive zip contenant le fichier à effacer.
 * \param fichierFrom Nom du fichier/dossier en entrée.
 * \param fichierTo Nom du fichier/dossier en sortie.
 *
 * \return ZIPZAP_SUCCESS : Retour OK ; ZIPZAP_FAILURE : Retour d'erreur.
 */
static int renommerFichierZip(const char* fichierZip, const char* fichierFrom, const char* fichierTo)
{
    int visu = 0;
    struct zip * f_zip=NULL;
    int err = 0;

    f_zip=zip_open(fichierZip,ZIP_CREATE,&err);
    /* s'il y a des erreurs */
    if(err != ZIP_ER_OK)
    {
        zip_error_to_str(buf_erreur, sizeof buf_erreur, err, errno);
        printf("Error %d : %s\n",err, buf_erreur);
        return ZIPZAP_FAILURE;
    }
    /* si le fichier zip n'est pas ouvert */
    if(f_zip==NULL)
    {
        printf("Erreur à l'ouverture du fichier %s\n", fichierZip);
        return ZIPZAP_FAILURE;
    }

    /* recherche de l'emplacement du fichier dans le zip */
    visu=zip_name_locate(f_zip,fichierFrom,0);
    if (visu==-1)
    {
        printf("Le fichier %s n'existe pas dans %s\n", fichierFrom, fichierZip);
        zip_close(f_zip);
        f_zip = NULL;
        return ZIPZAP_FAILURE;

    }


    /* si on demande de renommer un répertoire */
    if(fichierFrom[strlen(fichierFrom)-1]=='/')
    {
        char *ptr = NULL;
        int i = 0;
        int count = zip_get_num_files(f_zip);
        if(count==-1)
        {
            printf("Erreur à l'ouverture du fichier %s\n", fichierZip);
            return ZIPZAP_FAILURE;
        }
        for(i=0; i<count; i++)
        {

            /* on parcours tous les fichiers du zip pour savoir si un fichier est dans le dossier à supprimer */
            if( (ptr=strstr(zip_get_name(f_zip, i, ZIP_FL_UNCHANGED), fichierFrom)) != NULL)
            {
                /* si c'est le répertoire on lui applique un traitement particulier */
                if(strlen(fichierFrom)==strlen(zip_get_name(f_zip, i, ZIP_FL_UNCHANGED)))
                {
                    if(zip_rename(f_zip,i,fichierTo) == -1)
                    {

                        printf("%s\n", zip_strerror(f_zip));
                        zip_close(f_zip);
                        f_zip = NULL;
                        ptr = NULL;
                        return ZIPZAP_FAILURE;
                    }
                    printf("Le fichier %s a été renommé en %s dans %s\n", fichierFrom, fichierTo, fichierZip);
                }
                else
                {
                    /* si c'est un fichier de ce répertoire */
                    char *buf = NULL;
                    buf = malloc(FILENAME_MAX*sizeof(char));
                    if(buf==NULL)
                    {


                        printf("Erreur d'allocation mémoire.\n");
                        zip_close(f_zip);
                        f_zip = NULL;
                        FREE(buf);
                        ptr = NULL;
                        return ZIPZAP_FAILURE;
                    }

                    strcpy(buf,fichierTo);

                    strcat(buf,zip_get_name(f_zip, i, ZIP_FL_UNCHANGED)+strlen(fichierFrom));
                    printf("%s\n",buf);
                    if(zip_rename(f_zip,i,buf) == -1)
                    {

                        printf("%s\n", zip_strerror(f_zip));
                        zip_close(f_zip);
                        f_zip = NULL;
                        FREE(buf);
                        ptr = NULL;


                        return ZIPZAP_FAILURE;
                    }
                    printf("Le fichier %s a été renommé en %s dans %s\n", fichierFrom, fichierTo, fichierZip);
                    FREE(buf);
                }
            }
        }
        ptr = NULL;
    }
    else
    {
        /* sinon on renomme simplement le fichier trouvé par zip_name_locate à la position visu */
        if(zip_rename(f_zip,visu,fichierTo) == -1)
        {
            printf("%s\n", zip_strerror(f_zip));
            zip_close(f_zip);
            f_zip = NULL;
            return ZIPZAP_FAILURE;
        }
        printf("Le fichier %s a été renommé en %s dans %s\n", fichierFrom, fichierTo, fichierZip);
    }



    /* lecture terminée, fermeture de l'archive */

    zip_close(f_zip);
    f_zip = NULL;

    return ZIPZAP_SUCCESS;
}

/**
 * \fn static int remplacerFichierZip(const char* fichierZip, const char* fichier, int ajout)
 * \brief Remplace le fichier/dossier "fichier" dans l'archive zip "fichierZip".
 *
 * \param fichierZip Archive zip contenant le fichier à effacer.
 * \param fichier Nom du fichier/dossier à remplacer.
 * \param ajout Si le fichier n'existe pas dans l'archive, on l'ajoute ou non suivant la valeur de ajout (REPLACE_ADD ou REPLACE_NOT_ADD).
 *
 * \return ZIPZAP_SUCCESS : Retour OK ; ZIPZAP_FAILURE : Retour d'erreur.
 */
static int remplacerFichierZip(const char* fichierZip, const char* fichier, int ajout)
{

    /* Source de Troumad original : http://www.developpez.net/forums/d1012322/c-cpp/c/contribuez/faq-modifier-fichier-zip/ */
    /* modifié pour ajouter la gestion des erreurs et quelques fonctionnalités */

    int visu = 0;
    struct zip * f_zip=NULL;
    struct zip_source * n_zip=NULL;
    int err = 0;

    f_zip=zip_open(fichierZip,ZIP_CREATE,&err);
    /* s'il y a des erreurs */
    if(err != ZIP_ER_OK)
    {
        zip_error_to_str(buf_erreur, sizeof buf_erreur, err, errno);
        printf("Error %d : %s\n",err, buf_erreur);
        return ZIPZAP_FAILURE;
    }
    /* si le fichier zip n'est pas ouvert */
    if(f_zip==NULL)
    {
        printf("Erreur à l'ouverture du fichier %s\n", fichierZip);
        return ZIPZAP_FAILURE;
    }
    /* on met dans le zip_source le fichier que l'on veut remplacer */
    if((n_zip=zip_source_file(f_zip,fichier, (off_t)0, (off_t)0)) == NULL)
    {
        printf("%s\n", zip_strerror(f_zip));
        zip_close(f_zip);
        f_zip = NULL;
        return ZIPZAP_FAILURE;
    }


    /* recherche de l'emplacement du fichier dans le zip */
    visu=zip_name_locate(f_zip,fichier,0);
    if (visu==-1)
    {
        printf("Le fichier %s n'existe pas dans %s\n", fichier, fichierZip);
        if(ajout==REPLACE_ADD)
        {

            /* nouveau document dans le fichier zip  : le fichier n'y est pas */
            /* c'est là qu'on fixe le nom qu'aura le nouveau document dans le fichier zip */
            if(zip_add(f_zip,fichier,n_zip) == -1)
            {
                printf("%s\n", zip_strerror(f_zip));
                zip_close(f_zip);
                f_zip = NULL;
                zip_source_free(n_zip);
                n_zip = NULL;
                return ZIPZAP_FAILURE;
            }
            printf("Le fichier %s a été ajouté dans %s\n", fichier, fichierZip);
        }
        else if(ajout==REPLACE_NOT_ADD)
        {

            printf("Le fichier %s n'a pas été ajouté ou remplacé dans %s\n", fichier, fichierZip);


        }
        else
        {
            printf("Erreur d'utilisation de la fonction %s\n", __FUNCTION__);


        }
    }
    else
    {
        /* modification d'un document dans le fichier zip : le fichier est déjà dedans */
        /* notre document remplace le document qui ce trouve à l'emplacement visu */
        if(zip_replace(f_zip,visu,n_zip) == -1)
        {
            printf("%s\n", zip_strerror(f_zip));
            zip_close(f_zip);
            f_zip = NULL;
            zip_source_free(n_zip);
            n_zip = NULL;
            return ZIPZAP_FAILURE;
        }
        printf("Le fichier %s a été remplacé dans %s\n", fichier, fichierZip);

    }

    zip_close(f_zip);
    f_zip = NULL;
    zip_source_free(n_zip);
    n_zip = NULL;

    return ZIPZAP_SUCCESS;

}



/**
 * \fn static int ajouteDossier(const char *dir, struct zip *f_zip)
 * \brief Ajoute le dossier "dir" et tout ce qu'il contient dans l'archive zip "f_zip".
 *
 * \param dir Nom du dossier à ajouter dans l'archive zip.
 * \param f_zip Nom de l'archive zip.
 *
 * \return ZIPZAP_SUCCESS : Retour OK ; ZIPZAP_FAILURE : Retour d'erreur.
 */
static int ajouteDossier(const char *dir, struct zip *f_zip)
{
    /* TODO : pour windows */
#if defined(__POSIX_VISIBLE) || defined(_POSIX_C_SOURCE)
    struct stat f_stat;
    struct zip_source *doc = NULL;

    DIR *dirp = opendir(dir);
    struct dirent *dp = NULL;
    while ((dp = readdir(dirp)) != NULL)
    {
        if( ( (strcmp(dp->d_name,".")!=0) && (strcmp(dp->d_name,"..")!=0)) )
        {

            char str[FILENAME_MAX];
            /* on test les '/' */
            /* TODO : pour windows '\' ? */
            if( (dir[strlen(dir)-1]=='/') && (dp->d_name[0]=='/'))
            {
                strncpy(str, dir, strlen(dir)-2);
                strcat(str, dp->d_name);
            }
            else if( (dir[strlen(dir)-1]=='/') || (dp->d_name[0]=='/'))
                sprintf(str, "%s%s", dir, dp->d_name);
            else
                sprintf(str, "%s/%s", dir, dp->d_name);

            lstat(str, &f_stat);
            if(S_ISDIR(f_stat.st_mode))
            {
                /* si c'est un dossier on l'ajoute */
                if(zip_add_dir(f_zip, str) == -1)
                {
                    printf("%s\n", zip_strerror(f_zip));


                    (void)closedir(dirp);
                    return ZIPZAP_FAILURE;
                }
                /*et on relance la fonction*/
                if(ajouteDossier(str, f_zip)==ZIPZAP_FAILURE)
                {
                    printf("Erreur à l'ajout du dossier %s\n", str);


                    return ZIPZAP_FAILURE;
                }
            }
            else
            {
                /* sinon on ajoute le fichier */
                if((doc=zip_source_file(f_zip,str, (off_t)0, (off_t)0)) == NULL)
                {
                    printf("%s\n", zip_strerror(f_zip));


                    (void)closedir(dirp);
                    return ZIPZAP_FAILURE;
                }
                if(zip_add(f_zip, str, doc) == -1)
                {
                    printf("%s\n", zip_strerror(f_zip));


                    (void)closedir(dirp);
                    return ZIPZAP_FAILURE;
                }
            }
        }
    }

    (void)closedir(dirp);
#endif /* posix */
    return ZIPZAP_SUCCESS;
}


/**
* \fn static int verifPresenceFichier(const char* fichier)
* \brief Vérifie si le fichier/dossier "fichier" est présent dans l'archive ou non.
*        La fonction s'occupe de tester fichier et dossier que l'on rentre un fichier ou un dossier et inversemment.
*
* \param fichier Nom du fichier à tester dans l'archive zip.
*
* \return ZIPZAP_SUCCESS : Retour OK ; ZIPZAP_FAILURE : Retour d'erreur.
*/
static int verifPresenceFichier(struct zip *f_zip, const char* fichier)
{
    /* on vérifie que le fichier/dossier n'est pas déjà présent dans l'archive */
    /* on vérifie si c'est un dossier */
    if(fichier[strlen(fichier)-1] == '/')
    {
        /* on vérifie qu'un dossier ne porte pas déjà ce nom */
        if(zip_name_locate(f_zip,fichier,0)!=-1)
        {
            printf("Le dossier %s est déjà dans l'archive\n", fichier);
            return ZIPZAP_FAILURE;
        }

        /* on vérifie qu'un fichier ne porte pas déjà ce nom */
        char *str = strdup(fichier);
        str[strlen(str)-1] = '\0';
        if(zip_name_locate(f_zip,str,0)!=-1)
        {
            printf("Le fichier %s est déjà dans l'archive\n", str);
            FREE(str);

            return ZIPZAP_FAILURE;
        }
        FREE(str);

    }
    else
    {

        /* on vérifie qu'un fichier ne porte pas déjà ce nom */
        if(zip_name_locate(f_zip, fichier,0)!=-1)
        {
            printf("Le fichier %s est déjà dans l'archive\n", fichier);
            return ZIPZAP_FAILURE;
        }

        /* on vérifie qu'un dossier ne porte pas déjà ce nom */
        char *str = malloc((strlen(fichier)+1)*sizeof(char));
        memcpy(str, fichier, (strlen(fichier)+1)*sizeof(char));
        str[strlen(str)] = '/';
        str[strlen(str)+1] = '\0';

        if(zip_name_locate(f_zip,str,0)!=-1)
        {
            printf("Le dossier %s est déjà dans l'archive\n", str);
            FREE(str);

            return ZIPZAP_FAILURE;
        }
        FREE(str);

    }
    return ZIPZAP_SUCCESS;
}


/* http://fr.w3support.net/index.php?db=so&id=675039 */
/*
@(#)File:           $RCSfile: mkpath.c,v $
@(#)Version:        $Revision: 1.12 $
@(#)Last changed:   $Date: 2008/05/19 00:43:33 $
@(#)Purpose:        Create all directories in path
@(#)Author:         J Leffler
@(#)Copyright:      (C) JLSS 1990-91,1997-98,2001,2005,2008
@(#)Product:        :PRODUCT:
*/
static int do_mkdir(const char *path, mode_t mode)
{

    struct stat st;
    int status = 0;

    if(status != -1)
    {
        if (stat(path, &st) != 0)
        {
            /* Directory does not exist */
            if (mkdir(path, mode) != 0)
                status = -1;
        }
        else if (!S_ISDIR(st.st_mode))
        {
            errno = ENOTDIR;
            status = -1;
        }
    }

    return(status);
}
/**
** mkpath - ensure all directories in path exist
** Algorithm takes the pessimistic view and works top-down to ensure
** each directory in path exists, rather than optimistically creating
** the last element and working backwards.
*/
int mkpath(const char *path, mode_t mode)
{

    char           *pp;
    char           *sp;
    int             status = 0;
    char           *copypath = NULL;

    /* Debut des modifications de la source d'origine */
    char *rep = NULL;
    /* On ne créer le répertoire que s'il s'agit d'une véritable demande */
    /* Par exemple si on envoye foo/bar/file sans cette étape */
    /* la fonction va créer les répertoires foo/bar/file/ ce qui n'est pas désiré */
    if(path[strlen(path)-1]== '/')
    {
        rep=strdup(path);
    }
    else
    {
        char *tmp =strrchr(path, '/');
        if(tmp!=NULL)
        {
            size_t len = strlen(path)-strlen(tmp);
            rep=malloc(len+1);
            if(rep == NULL)
            {
                status = -1;
            }
            else
            {
                memset(rep, 0, len+1);
                memcpy(rep, path, len);
            }
        }
        tmp=NULL;
    }
    /* Fin des modifications de la source d'origine */
    /* Pour la suite path est remplacé par rep */
    if(status!=-1)
    {

        copypath = strdup(rep);
        pp = copypath;
        while (status == 0 && (sp = strchr(pp, '/')) != 0)
        {
            if (sp != pp)
            {
                /* Neither root nor double slash in path */
                *sp = '\0';
                status = do_mkdir(copypath, mode);
                *sp = '/';
            }
            pp = sp + 1;
        }
        if (status == 0)
            status = do_mkdir(rep, mode);
        FREE(copypath);
    }
    FREE(rep);
    return (status);
}


