int COsFileFuncs::open()

in lib/core/COsFileFuncs_Windows.cc [65:151]


int COsFileFuncs::open(const char* path, int oflag, TMode pmode) {
    // To allow the underlying file to be renamed, we have to resort to using
    // the Windows API file functions.  Otherwise we can use the POSIX
    // compatibility layer.
    if ((oflag & RENAMABLE) == 0) {
        // This is the simple case.  Windows won't allow the file to be renamed
        // whilst it's open.
        return ::_open(path, oflag, pmode);
    }

    // Determine the correct access flags
    DWORD desiredAccess(GENERIC_READ);
    if ((oflag & RDWR) != 0) {
        desiredAccess = GENERIC_READ | GENERIC_WRITE;
    } else if ((oflag & WRONLY) != 0) {
        desiredAccess = GENERIC_WRITE;
    }

    DWORD creationDisposition(0);
    switch (oflag & (CREAT | EXCL | TRUNC)) {
    case CREAT:
        creationDisposition = OPEN_ALWAYS;
        break;
    case CREAT | EXCL:
    case CREAT | TRUNC | EXCL:
        creationDisposition = CREATE_NEW;
        break;
    case TRUNC:
        creationDisposition = TRUNCATE_EXISTING;
        break;
    case TRUNC | EXCL:
        // This doesn't make sense
        errno = EINVAL;
        return -1;
    case CREAT | TRUNC:
        creationDisposition = CREATE_ALWAYS;
        break;
    default:
        creationDisposition = OPEN_EXISTING;
        break;
    }

    DWORD attributes(FILE_ATTRIBUTE_NORMAL);
    if ((oflag & CREAT) != 0 && (pmode & S_IWRITE) == 0) {
        attributes = FILE_ATTRIBUTE_READONLY;
    }

    HANDLE handle = CreateFile(path, desiredAccess,
                               FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
                               0, creationDisposition, attributes, 0);
    if (handle == INVALID_HANDLE_VALUE) {
        switch (GetLastError()) {
        case ERROR_FILE_NOT_FOUND:
        case ERROR_PATH_NOT_FOUND:
        case ERROR_INVALID_DRIVE:
        case ERROR_BAD_PATHNAME:
            errno = ENOENT;
            break;
        case ERROR_TOO_MANY_OPEN_FILES:
            errno = EMFILE;
            break;
        case ERROR_ACCESS_DENIED:
        case ERROR_NETWORK_ACCESS_DENIED:
        case ERROR_LOCK_VIOLATION:
        case ERROR_DRIVE_LOCKED:
            errno = EACCES;
            break;
        case ERROR_INVALID_HANDLE:
            errno = EBADF;
            break;
        case ERROR_NOT_ENOUGH_MEMORY:
            errno = ENOMEM;
            break;
        case ERROR_DISK_FULL:
            errno = ENOSPC;
            break;
        default:
            errno = EINVAL;
            break;
        }
        return -1;
    }

    // Convert the Windows handle to a POSIX compatibility layer file descriptor
    int filteredFlags(oflag & (TEXT | RDONLY | APPEND));
    return ::_open_osfhandle(reinterpret_cast<intptr_t>(handle), filteredFlags);
}