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; }
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; }