osd_file::error osd_file::remove(std::string const &filename) { if (::unlink(filename.c_str()) < -1) return errno_to_file_error(errno); else return error::NONE; }
osd_file::error osd_get_full_path(std::string &dst, std::string const &path) { try { #if defined(WIN32) std::vector<char> path_buffer(MAX_PATH); if (::_fullpath(&path_buffer[0], path.c_str(), MAX_PATH)) { dst = &path_buffer[0]; return osd_file::error::NONE; } else { return osd_file::error::FAILURE; } #else std::unique_ptr<char, void (*)(void *)> canonical(::realpath(path.c_str(), nullptr), &std::free); if (canonical) { dst = canonical.get(); return osd_file::error::NONE; } std::vector<char> path_buffer(PATH_MAX); if (::realpath(path.c_str(), &path_buffer[0])) { dst = &path_buffer[0]; return osd_file::error::NONE; } else if (path[0] == PATHSEPCH) { dst = path; return osd_file::error::NONE; } else { while (!::getcwd(&path_buffer[0], path_buffer.size())) { if (errno != ERANGE) return errno_to_file_error(errno); else path_buffer.resize(path_buffer.size() * 2); } dst.assign(&path_buffer[0]).push_back(PATHSEPCH); dst.append(path); return osd_file::error::NONE; } #endif } catch (...) { return osd_file::error::OUT_OF_MEMORY; } }
osd_file::error osd_file::open(std::string const &path, std::uint32_t openflags, ptr &file, std::uint64_t &filesize) { std::string dst; if (posix_check_socket_path(path)) return posix_open_socket(path, openflags, file, filesize); else if (posix_check_ptty_path(path)) return posix_open_ptty(openflags, file, filesize, dst); // select the file open modes int access; if (openflags & OPEN_FLAG_WRITE) { access = (openflags & OPEN_FLAG_READ) ? O_RDWR : O_WRONLY; access |= (openflags & OPEN_FLAG_CREATE) ? (O_CREAT | O_TRUNC) : 0; } else if (openflags & OPEN_FLAG_READ) { access = O_RDONLY; } else { return error::INVALID_ACCESS; } #if defined(WIN32) access |= O_BINARY; #endif // convert the path into something compatible dst = path; #if defined(WIN32) for (auto it = dst.begin(); it != dst.end(); ++it) *it = (INVPATHSEPCH == *it) ? PATHSEPCH : *it; #endif osd_subst_env(dst, dst); // attempt to open the file int fd = -1; #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(__HAIKU__) || defined(WIN32) || defined(SDLMAME_NO64BITIO) || defined(__ANDROID__) fd = ::open(dst.c_str(), access, 0666); #else fd = ::open64(dst.c_str(), access, 0666); #endif if (fd < 0) { // create the path if necessary if ((openflags & OPEN_FLAG_CREATE) && (openflags & OPEN_FLAG_CREATE_PATHS)) { auto const pathsep = dst.rfind(PATHSEPCH); if (pathsep != std::string::npos) { // create the path up to the file osd_file::error const error = create_path_recursive(dst.substr(0, pathsep)); // attempt to reopen the file if (error == osd_file::error::NONE) { #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(__HAIKU__) || defined(WIN32) || defined(SDLMAME_NO64BITIO) || defined(__ANDROID__) fd = ::open(dst.c_str(), access, 0666); #else fd = ::open64(dst.c_str(), access, 0666); #endif } } } // if we still failed, clean up and osd_free if (fd < 0) { return errno_to_file_error(errno); } } // get the file size #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(__HAIKU__) || defined(WIN32) || defined(SDLMAME_NO64BITIO) || defined(__ANDROID__) struct stat st; if (::fstat(fd, &st) < 0) #else struct stat64 st; if (::fstat64(fd, &st) < 0) #endif { int const error = errno; ::close(fd); return errno_to_file_error(error); } filesize = std::uint64_t(std::make_unsigned_t<decltype(st.st_size)>(st.st_size)); try { file = std::make_unique<posix_osd_file>(fd); return error::NONE; } catch (...) { ::close(fd); return error::OUT_OF_MEMORY; } }
osd_file::error posix_open_socket(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize) { char hostname[256]; int port; std::sscanf(&path[strlen(posixfile_socket_identifier)], "%255[^:]:%d", hostname, &port); struct hostent const *const localhost = ::gethostbyname(hostname); if (!localhost) return osd_file::error::NOT_FOUND; struct sockaddr_in sai; memset(&sai, 0, sizeof(sai)); sai.sin_family = AF_INET; sai.sin_port = htons(port); sai.sin_addr = *reinterpret_cast<struct in_addr *>(localhost->h_addr); int const sock = ::socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) return errno_to_file_error(errno); int const flag = 1; if (::setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<const char *>(&flag), sizeof(flag)) < 0) { int const err = errno; ::close(sock); return errno_to_file_error(err); } if (::setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<const char *>(&flag), sizeof(flag)) < 0) { int const err = errno; ::close(sock); return errno_to_file_error(err); } // listening socket support if (openflags & OPEN_FLAG_CREATE) { //printf("Listening for client at '%s' on port '%d'\n", hostname, port); // bind socket... if (::bind(sock, reinterpret_cast<struct sockaddr const *>(&sai), sizeof(struct sockaddr)) < 0) { int const err = errno; ::close(sock); return errno_to_file_error(err); } // start to listen... if (::listen(sock, 1) < 0) { int const err = errno; ::close(sock); return errno_to_file_error(err); } // mark socket as "listening" try { file = std::make_unique<posix_osd_socket>(sock, true); filesize = 0; return osd_file::error::NONE; } catch (...) { ::close(sock); return osd_file::error::OUT_OF_MEMORY; } } else { //printf("Connecting to server '%s' on port '%d'\n", hostname, port); if (::connect(sock, reinterpret_cast<struct sockaddr const *>(&sai), sizeof(struct sockaddr)) < 0) { ::close(sock); return osd_file::error::ACCESS_DENIED; // have to return this value or bitb won't try to bind on connect failure } try { file = std::make_unique<posix_osd_socket>(sock, false); filesize = 0; return osd_file::error::NONE; } catch (...) { ::close(sock); return osd_file::error::OUT_OF_MEMORY; } } }