+++ /dev/null
-/*
- * Copyright (c) 2000-2001,2003-2004 Apple Computer, Inc. All Rights Reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-
-
-//
-// unix++ - C++ layer for basic UNIX facilities
-//
-#include "unix++.h"
-#include <security_utilities/memutils.h>
-#include <security_utilities/debugging.h>
-#include <sys/xattr.h>
-#include <cstdarg>
-
-
-namespace Security {
-namespace UnixPlusPlus {
-
-using LowLevelMemoryUtilities::increment;
-
-
-//
-// Canonical open of a file descriptor. All other open operations channel through this.
-// Note that we abuse the S_IFMT mode flags as operational options.
-//
-void FileDesc::open(const char *path, int flags, mode_t mode)
-{
- if ((mFd = ::open(path, flags, mode & ~S_IFMT)) == -1) {
- if (errno == ENOENT && (mode & S_IFMT) == modeMissingOk) {
- return;
- } else {
- UnixError::throwMe();
- }
- }
- mAtEnd = false;
- secdebug("unixio", "open(%s,0x%x,0x%x) = %d", path, flags, mode, mFd);
-}
-
-void FileDesc::close()
-{
- if (mFd >= 0) {
- checkError(::close(mFd));
- secdebug("unixio", "close(%d)", mFd);
- mFd = invalidFd;
- }
-}
-
-
-//
-// Filedescoid operations
-//
-size_t FileDesc::read(void *addr, size_t length)
-{
- switch (ssize_t rc = ::read(mFd, addr, length)) {
- case 0: // end-of-source
- if (length == 0) { // check for errors, but don't set mAtEnd unless we have to
- secdebug("unixio", "%d zero read (ignored)", mFd);
- return 0;
- }
- mAtEnd = true;
- secdebug("unixio", "%d end of data", mFd);
- return 0;
- case -1: // error
- if (errno == EAGAIN)
- return 0; // no data, unknown end-of-source status
- UnixError::throwMe(); // throw error
- default: // have data
- return rc;
- }
-}
-
-size_t FileDesc::write(const void *addr, size_t length)
-{
- ssize_t rc = ::write(mFd, addr, length);
- if (rc == -1) {
- if (errno == EAGAIN)
- return 0;
- UnixError::throwMe();
- }
- return rc;
-}
-
-
-//
-// I/O with integral positioning.
-// These don't affect file position and the atEnd() flag; and they
-// don't make allowances for asynchronous I/O.
-//
-size_t FileDesc::read(void *addr, size_t length, size_t position)
-{
- return checkError(::pread(mFd, addr, length, position));
-}
-
-size_t FileDesc::write(const void *addr, size_t length, size_t position)
-{
- return checkError(::pwrite(mFd, addr, length, position));
-}
-
-
-//
-// Waiting (repeating) I/O
-//
-size_t FileDesc::readAll(void *addr, size_t length)
-{
- size_t total = 0;
- while (length > 0 && !atEnd()) {
- size_t size = read(addr, length);
- addr = increment(addr, size);
- length -= size;
- total += size;
- }
- return total;
-}
-
-size_t FileDesc::readAll(string &value)
-{
- string s;
- while (!atEnd()) {
- char buffer[256];
- if (size_t size = read(buffer, sizeof(buffer))) {
- s += string(buffer, size);
- continue;
- }
- }
- swap(value, s);
- return value.length();
-}
-
-
-void FileDesc::writeAll(const void *addr, size_t length)
-{
- while (length > 0) {
- size_t size = write(addr, length);
- addr = increment(addr, size);
- length -= size;
- }
-}
-
-
-//
-// Seeking
-//
-#warning Cast to size_t may loose precision, only a problem for large files.
-
-size_t FileDesc::seek(size_t position, int whence)
-{
- return (size_t)checkError(::lseek(mFd, position, whence));
-}
-
-size_t FileDesc::position() const
-{
- return (size_t)checkError(::lseek(mFd, 0, SEEK_CUR));
-}
-
-
-//
-// Mmap support
-//
-void *FileDesc::mmap(int prot, size_t length, int flags, size_t offset, void *addr)
-{
- if (!(flags & (MAP_PRIVATE | MAP_SHARED))) // one is required
- flags |= MAP_PRIVATE;
- void *result = ::mmap(addr, length ? length : fileSize(), prot, flags, mFd, offset);
- if (result == MAP_FAILED)
- UnixError::throwMe();
- return result;
-}
-
-
-//
-// Basic fcntl support
-//
-int FileDesc::fcntl(int cmd, void *arg) const
-{
- int rc = ::fcntl(mFd, cmd, arg);
- secdebug("unixio", "%d fcntl(%d,%p) = %d", mFd, cmd, arg, rc);
- return checkError(rc);
-}
-
-
-//
-// Nice fcntl forms
-//
-void FileDesc::setFlag(int flag, bool on) const
-{
- if (flag) { // if there's anything at all to do...
- int oldFlags = flags();
- flags(on ? (oldFlags | flag) : (oldFlags & ~flag));
- }
-}
-
-
-//
-// Duplication operations
-//
-FileDesc FileDesc::dup() const
-{
- return FileDesc(checkError(::dup(mFd)), atEnd());
-}
-
-FileDesc FileDesc::dup(int newFd) const
-{
- return FileDesc(checkError(::dup2(mFd, newFd)), atEnd());
-}
-
-
-//
-// Advisory locking, fcntl style
-//
-void FileDesc::lock(int type, const Pos &pos)
-{
- LockArgs args(type, pos);
- IFDEBUG(args.debug(fd(), "lock"));
- checkError(fcntl(F_SETLKW, &args));
-}
-
-bool FileDesc::tryLock(int type, const Pos &pos)
-{
- LockArgs args(type, pos);
- IFDEBUG(args.debug(fd(), "tryLock"));
- try {
- fcntl(F_SETLK, &args);
- return true;
- } catch (const UnixError &err) {
- if (err.error == EAGAIN)
- return false;
- else
- throw;
- }
-}
-
-#if !defined(NDEBUG)
-
-void FileDesc::LockArgs::debug(int fd, const char *what)
-{
- secdebug("fdlock", "%d %s %s:%ld(%ld)", fd, what,
- (l_whence == SEEK_SET) ? "ABS" : (l_whence == SEEK_CUR) ? "REL" : "END",
- long(l_start), long(l_len));
-}
-
-#endif //NDEBUG
-
-
-//
-// ioctl support
-//
-int FileDesc::ioctl(int cmd, void *arg) const
-{
- int rc = ::ioctl(mFd, cmd, arg);
- if (rc == -1)
- UnixError::throwMe();
- return rc;
-}
-
-
-//
-// Xattr support
-//
-void FileDesc::setAttr(const char *name, const void *value, size_t length,
- u_int32_t position /* = 0 */, int options /* = 0 */)
-{
- checkError(::fsetxattr(mFd, name, value, length, position, options));
-}
-
-ssize_t FileDesc::getAttrLength(const char *name)
-{
- ssize_t rc = ::fgetxattr(mFd, name, NULL, 0, 0, 0);
- if (rc == -1)
- switch (errno) {
- case ENOATTR:
- return -1;
- default:
- UnixError::throwMe();
- }
- return rc;
-}
-
-ssize_t FileDesc::getAttr(const char *name, void *value, size_t length,
- u_int32_t position /* = 0 */, int options /* = 0 */)
-{
- ssize_t rc = ::fgetxattr(mFd, name, value, length, position, options);
- if (rc == -1)
- switch (errno) {
- case ENOATTR:
- return -1;
- default:
- UnixError::throwMe();
- }
- return rc;
-}
-
-void FileDesc::removeAttr(const char *name, int options /* = 0 */)
-{
- if (::fremovexattr(mFd, name, options))
- switch (errno) {
- case ENOATTR:
- if (!(options & XATTR_REPLACE)) // somewhat mis-using an API flag here...
- return; // attribute not found; we'll call that okay
- // fall through
- default:
- UnixError::throwMe();
- }
-}
-
-size_t FileDesc::listAttr(char *value, size_t length, int options /* = 0 */)
-{
- return checkError(::flistxattr(mFd, value, length, options));
-}
-
-
-void FileDesc::setAttr(const std::string &name, const std::string &value, int options /* = 0 */)
-{
- return setAttr(name, value.c_str(), value.size(), 0, options);
-}
-
-std::string FileDesc::getAttr(const std::string &name, int options /* = 0 */)
-{
- char buffer[4096]; //@@@ auto-expand?
- ssize_t length = getAttr(name, buffer, sizeof(buffer), 0, options);
- if (length >= 0)
- return string(buffer, length);
- else
- return string();
-}
-
-bool FileDesc::isPlainFile(const std::string &path)
-{
- UnixStat st1, st2;
- this->fstat(st1);
- if (::lstat(path.c_str(), &st2))
- UnixError::throwMe();
-
- return (st1.st_ino == st2.st_ino && S_ISREG(st2.st_mode));
-}
-
-
-//
-// Stat support
-//
-void FileDesc::fstat(UnixStat &st) const
-{
- if (::fstat(mFd, &st))
- UnixError::throwMe();
-}
-
-size_t FileDesc::fileSize() const
-{
- struct stat st;
- fstat(st);
- return (size_t)st.st_size;
-}
-
-bool FileDesc::isA(int mode) const
-{
- struct stat st;
- fstat(st);
- return (st.st_mode & S_IFMT) == mode;
-}
-
-
-void FileDesc::chown(uid_t uid)
-{
- checkError(::fchown(mFd, uid, gid_t(-1)));
-}
-
-void FileDesc::chown(uid_t uid, gid_t gid)
-{
- checkError(::fchown(mFd, uid, gid));
-}
-
-void FileDesc::chgrp(gid_t gid)
-{
- checkError(::fchown(mFd, uid_t(-1), gid));
-}
-
-void FileDesc::chmod(mode_t mode)
-{
- checkError(::fchmod(mFd, mode));
-}
-
-void FileDesc::chflags(u_int flags)
-{
- checkError(::fchflags(mFd, flags));
-}
-
-
-FILE *FileDesc::fdopen(const char *form)
-{
- //@@@ pick default value for 'form' based on chracteristics of mFd
- return ::fdopen(mFd, form);
-}
-
-
-//
-// Signals and signal masks
-//
-SigSet sigMask(SigSet set, int how /* = SIG_SETMASK */)
-{
- sigset_t old;
- checkError(::sigprocmask(how, &set.value(), &old));
- return old;
-}
-
-
-//
-// Make or use a directory, open-style.
-//
-// Flags are to be interpreted like open(2) flags; particularly
-// O_CREAT make the directory if not present
-// O_EXCL fail if the directory is present
-// Other open(2) flags are currently ignored.
-//
-// Yes, it's a function.
-//
-void makedir(const char *path, int flags, mode_t mode)
-{
- struct stat st;
- if (!stat(path, &st)) {
- if (flags & O_EXCL)
- UnixError::throwMe(EEXIST);
- if (!S_ISDIR(st.st_mode))
- UnixError::throwMe(ENOTDIR);
- secdebug("makedir", "%s exists", path);
- return;
- }
-
- // stat failed
- if (errno != ENOENT || !(flags & O_CREAT))
- UnixError::throwMe();
-
- // ENOENT and creation enabled
- if (::mkdir(path, mode)) {
- if (errno == EEXIST && !(flags & O_EXCL))
- return; // fine (race condition, resolved)
- UnixError::throwMe();
- }
- secdebug("makedir", "%s created", path);
-}
-
-
-//
-// Open, read/write, close a (small) file on disk
-//
-int ffprintf(const char *path, int flags, mode_t mode, const char *format, ...)
-{
- FileDesc fd(path, flags, mode);
- FILE *f = fd.fdopen("w");
- va_list args;
- va_start(args, format);
- int rc = vfprintf(f, format, args);
- va_end(args);
- if (fclose(f))
- UnixError::throwMe();
- return rc;
-}
-
-int ffscanf(const char *path, const char *format, ...)
-{
- if (FILE *f = fopen(path, "r")) {
- va_list args;
- va_start(args, format);
- int rc = vfscanf(f, format, args);
- va_end(args);
- if (!fclose(f))
- return rc;
- }
- UnixError::throwMe();
-}
-
-
-} // end namespace IPPlusPlus
-} // end namespace Security