static jobject CreateFileInfo(JNIEnv *env, jstring path, bool append, LPWIN32_FIND_DATA lpData, jclass cls) {
    jobject o = env->AllocObject(cls);
    if (o == NULL) {
        return NULL;
    }

    jstring fileName = env->NewString((jchar*)lpData->cFileName, (jsize)wcslen(lpData->cFileName));
    if (fileName == NULL) {
        return NULL;
    }
    env->SetObjectField(o, nameID, fileName);

    bool read = false;
    if (IS_SET(lpData->dwFileAttributes, FILE_ATTRIBUTE_REPARSE_POINT) && IS_SET(lpData->dwReserved0, IO_REPARSE_TAG_SYMLINK)) {
        int nameLen = env->GetStringLength(path) + wcslen(lpData->cFileName) + 2;
        wchar_t *lpName = (wchar_t *)malloc(nameLen * sizeof(wchar_t));

        if (lpName != NULL) {
            const jchar *dirName = env->GetStringChars(path, 0);
            wcscpy_s(lpName, nameLen, (LPCWSTR)dirName);
            env->ReleaseStringChars(path, dirName);
            if (append) {
                wcscat_s(lpName, nameLen, L"\\");
                wcscat_s(lpName, nameLen, lpData->cFileName);
            }

            // read symlink target attributes
            HANDLE th = CreateFile(lpName, FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
                                   OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
            if (th != INVALID_HANDLE_VALUE) {
                BY_HANDLE_FILE_INFORMATION targetData;
                if (GetFileInformationByHandle(th, &targetData)) {
                    env->SetIntField(o, attributesID, targetData.dwFileAttributes);
                    env->SetLongField(o, timestampID, pairToInt64(targetData.ftLastWriteTime.dwLowDateTime, targetData.ftLastWriteTime.dwHighDateTime));
                    env->SetLongField(o, lengthID, pairToInt64(targetData.nFileSizeLow, targetData.nFileSizeHigh));
                    read = true;
                }
                CloseHandle(th);
            }

            free(lpName);
        }
    }

    if (!read) {
        env->SetIntField(o, attributesID, lpData->dwFileAttributes);
        env->SetLongField(o, timestampID, pairToInt64(lpData->ftLastWriteTime.dwLowDateTime, lpData->ftLastWriteTime.dwHighDateTime));
        env->SetLongField(o, lengthID, pairToInt64(lpData->nFileSizeLow, lpData->nFileSizeHigh));
    }

    return o;
}
Example #2
0
static jobject CreateFileInfo(JNIEnv *env, jstring path, bool append, LPWIN32_FIND_DATA lpData, jclass fileInfoClass) {
    DWORD attributes = lpData->dwFileAttributes;
    LONGLONG timestamp = pairToInt64(lpData->ftLastWriteTime.dwLowDateTime, lpData->ftLastWriteTime.dwHighDateTime);
    LONGLONG length = pairToInt64(lpData->nFileSizeLow, lpData->nFileSizeHigh);

    if (IS_SET(attributes, FILE_ATTRIBUTE_REPARSE_POINT)) {
        if (IS_SET(lpData->dwReserved0, IO_REPARSE_TAG_SYMLINK)) {
            attributes = BROKEN_SYMLINK_ATTR;
            timestamp = 0;
            length = 0;

            const jchar *dirName = env->GetStringChars(path, 0);
            wchar_t *fullPath = (wchar_t *)dirName;

            if (append) {
                size_t nameLen = env->GetStringLength(path) + wcslen(lpData->cFileName) + 2;
                fullPath = (wchar_t *)malloc(nameLen * sizeof(wchar_t));
                if (fullPath != NULL) {
                    wcscpy_s(fullPath, nameLen, (LPCWSTR)dirName);
                    wcscat_s(fullPath, nameLen, L"\\");
                    wcscat_s(fullPath, nameLen, lpData->cFileName);
                }
            }

            if (fullPath != NULL) {
                // read symlink target attributes
                HANDLE h = CreateFile(fullPath, 0, FILE_SHARE_ATTRIBUTES, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
                if (h != INVALID_HANDLE_VALUE) {
                    BY_HANDLE_FILE_INFORMATION targetData;
                    if (GetFileInformationByHandle(h, &targetData)) {
                        attributes = targetData.dwFileAttributes | FILE_ATTRIBUTE_REPARSE_POINT;
                        timestamp = pairToInt64(targetData.ftLastWriteTime.dwLowDateTime, targetData.ftLastWriteTime.dwHighDateTime);
                        length = pairToInt64(targetData.nFileSizeLow, targetData.nFileSizeHigh);
                    }
                    CloseHandle(h);
                }

                if (append) {
                    free(fullPath);
                }
            }

            env->ReleaseStringChars(path, dirName);
        }
        else {
            attributes &= (~ FILE_ATTRIBUTE_REPARSE_POINT);  // keep reparse flag only for symlinks
        }
    }

    jobject o = env->AllocObject(fileInfoClass);
    if (o == NULL) {
        return NULL;
    }

    jstring fileName = env->NewString((jchar*)lpData->cFileName, (jsize)wcslen(lpData->cFileName));
    if (fileName == NULL) {
        return NULL;
    }
    env->SetObjectField(o, nameID, fileName);

    env->SetIntField(o, attributesID, attributes);
    env->SetLongField(o, timestampID, timestamp);
    env->SetLongField(o, lengthID, length);

    return o;
}