Files
panda3d/direct/src/plugin/mkdir_complete.cxx
Sam Edwards b2bfb31114 general: Remove using std::* from headers
Also remove most `using namespace std;` statements. The only one that remains is in py_panda.h.

Closes #350
Closes #335
2018-06-14 16:04:49 +02:00

225 lines
5.7 KiB
C++

/**
* PANDA 3D SOFTWARE
* Copyright (c) Carnegie Mellon University. All rights reserved.
*
* All use of this software is subject to the terms of the revised BSD
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* @file mkdir_complete.cxx
* @author drose
* @date 2009-06-29
*/
#include "mkdir_complete.h"
#include "is_pathsep.h"
#include "wstring_encode.h"
#ifdef _WIN32
#include <windows.h>
#include <io.h> // chmod()
#else
#include <fcntl.h>
#include <sys/stat.h> // for mkdir()
#include <errno.h>
#include <string.h> // strerror()
#include <unistd.h>
#endif
using std::ostream;
using std::string;
using std::wstring;
/**
* Returns the directory component of the indicated pathname, or the empty
* string if there is no directory prefix.
*/
static string
get_dirname(const string &filename) {
size_t p = filename.length();
while (p > 0) {
--p;
if (is_pathsep(filename[p])) {
return filename.substr(0, p);
}
}
return string();
}
#ifdef _WIN32
/**
* The wide-character implementation of get_dirname(). Only implemented (and
* needed) on Windows.
*/
static wstring
get_dirname_w(const wstring &filename) {
size_t p = filename.length();
while (p > 0) {
--p;
if (is_pathsep(filename[p])) {
return filename.substr(0, p);
}
}
return wstring();
}
#endif // _WIN32
/**
* Creates a new directory, with normal access privileges. Returns true on
* success, false on failure. Will create intervening directories if
* necessary.
*/
bool
mkdir_complete(const string &dirname, ostream &logfile) {
#ifdef _WIN32
wstring dirname_w;
if (!string_to_wstring(dirname_w, dirname)) {
return false;
}
return mkdir_complete_w(dirname_w, logfile);
#else //_WIN32
if (mkdir(dirname.c_str(), 0755) == 0) {
// Success!
return true;
}
// Failed.
if (errno == EEXIST) {
// Not really an error: the directory is already there.
return true;
}
if (errno == ENOENT || errno == EACCES) {
// We need to make the parent directory first.
string parent = get_dirname(dirname);
if (!parent.empty() && mkdir_complete(parent, logfile)) {
// Parent successfully created. Try again to make the child.
if (mkdir(dirname.c_str(), 0755) == 0) {
// Got it!
return true;
}
// Couldn't create the directory. :(
logfile
<< "Couldn't create " << dirname << ": " << strerror(errno) << "\n";
}
}
return false;
#endif // _WIN32
}
/**
* Creates a new file with normal access priviledges. Returns true on
* success, false on failure. This will create intervening directories if
* needed.
*/
bool
mkfile_complete(const string &filename, ostream &logfile) {
#ifdef _WIN32
wstring filename_w;
if (!string_to_wstring(filename_w, filename)) {
return false;
}
return mkfile_complete_w(filename_w, logfile);
#else // _WIN32
// Make sure we delete any previously-existing file first.
unlink(filename.c_str());
int fd = creat(filename.c_str(), 0755);
if (fd == -1) {
// Try to make the parent directory first.
string parent = get_dirname(filename);
if (!parent.empty() && mkdir_complete(parent, logfile)) {
// Parent successfully created. Try again to make the file.
fd = creat(filename.c_str(), 0755);
}
if (fd == -1) {
logfile
<< "Couldn't create " << filename << ": " << strerror(errno) << "\n";
return false;
}
}
close(fd);
return true;
#endif // _WIN32
}
#ifdef _WIN32
/**
* The wide-character implementation of mkdir_complete(). Only implemented
* (and needed) on Windows.
*/
bool
mkdir_complete_w(const wstring &dirname, ostream &logfile) {
if (CreateDirectoryW(dirname.c_str(), nullptr) != 0) {
// Success!
return true;
}
// Failed.
DWORD last_error = GetLastError();
if (last_error == ERROR_ALREADY_EXISTS) {
// Not really an error: the directory is already there.
return true;
}
if (last_error == ERROR_PATH_NOT_FOUND) {
// We need to make the parent directory first.
wstring parent = get_dirname_w(dirname);
if (!parent.empty() && mkdir_complete_w(parent, logfile)) {
// Parent successfully created. Try again to make the child.
if (CreateDirectoryW(dirname.c_str(), nullptr) != 0) {
// Got it!
return true;
}
logfile
<< "Couldn't create " << dirname << "\n";
}
}
return false;
}
#endif // _WIN32
#ifdef _WIN32
/**
* The wide-character implementation of mkfile_complete(). Only implemented
* (and needed) on Windows.
*/
bool
mkfile_complete_w(const wstring &filename, ostream &logfile) {
// Make sure we delete any previously-existing file first.
// Windows can't delete a file if it's read-only. Weird.
_wchmod(filename.c_str(), 0644);
_wunlink(filename.c_str());
HANDLE file = CreateFileW(filename.c_str(), GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
if (file == INVALID_HANDLE_VALUE) {
// Try to make the parent directory first.
wstring parent = get_dirname_w(filename);
if (!parent.empty() && mkdir_complete_w(parent, logfile)) {
// Parent successfully created. Try again to make the file.
file = CreateFileW(filename.c_str(), GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
}
if (file == INVALID_HANDLE_VALUE) {
logfile
<< "Couldn't create " << filename << "\n";
return false;
}
}
CloseHandle(file);
return true;
}
#endif // _WIN32