середу, 21 квітня 2010 р.

Про велосипеди

Мова піде про винахід колеса для кожного окремого воза. Вкотре знадобилася функція, яка б виконувала mkdir -p, тобто рекурсивно створювала директорії по заданому шляху. mkdir(2) справляється тільки тоді, коли всі батьківські директорії вже існують, а нам саме треба створити бракуючі.

Найдоступніші замінники:

  • system ("mkdir -p a/b/c/d")

    Для простої операції створює процес оболонки, а та ще один для mkdir — зажирно.

  • boost::filesystem::create_directories ("a/b/c/d")

    Цей тягне за собою не потрібну ні для чого іншого бібліотеку, жаба душить. Крім того, немає можливості задати права доступу до нових каталогів.

Ретельніший пошук показав, що у світі Unix кожен сам собі пише потрібну приблуду. А раз так, то й я не хотів зостатися осторонь. Нічого в ній особливого немає, тому прошу смакувати (C++):

        
//
// Mkdir.cc
//
//     Created: 21.04.2010
//      Author: A. Sakhnik
//

#include "Mkdir.hh"

#include <fcntl.h>
#include <errno.h>
#include <string>
#include <syslog.h>

using namespace std;

static int mkdir_if_missing (char const* path, mode_t mode)
{
    struct stat buf;
    if (-1 != ::lstat (path, &buf))
    {
        if (S_ISDIR (buf.st_mode))
            return 0;               // The path is a directory, OK
        errno = ENOTDIR;
        return -1;                  // The path exists, and isn't a directory
    }
    if (errno != ENOENT)
        return -1;                  // Something bad happened
    if (-1 == ::mkdir (path, mode))
        return -1;                  // Wasn't able to create the directory
    return 0;                       // We were lucky enough indeed
}

// Create directory recursively
int mkdir_p (char const* path, mode_t mode)
{
    string parents;                 // Partial paths a, a/b, a/b/c etc

    for (const char *next = strchr (path, '/'), *prev = path;
         next;
         prev = next, next = strchr (next + 1, '/'))
    {
        parents.insert (parents.end(), prev, next); // Consider next component
        if (parents.empty())
            continue;    // Omit root directory for absolute path
        if (-1 == mkdir_if_missing (parents.c_str(), mode))
            return -1;
    }
    return mkdir_if_missing (path, mode); // Create final component
}

// vim: set et ts=4 sw=4:

      

Немає коментарів:

Дописати коментар