Konwersja ścieżki do pliku z case insensitive do case sensitive

0

Problem rozwiązany, ale niezbyt ładnie...

Jestem nekromantą i reanimuję stary serwis napisany w PHP.
Miał on jakiś CMS, który bazę danych prowadził w plikach tekstowych - co akurat mało przeszkadza, bo mogę sobie łatwo wszystkie newsy przetworzyć na markdown (Jekyll - GitHub Pages) moim skryptem.

Newsy miały do siebie przypisane zdjęcia i o dziwo niektóre wpisy w bazie miały nazwy plików zapisane inną wielkością znaków, niż pliki na serwerze. Np. zamiast *.jpg, było *.JPG.
Więc po przejechaniu moim skryptem na wygenerowanych stronach niektóre zdjęcia się nie ładowały.
Więc musiałem dodać weryfikację ścieżki pliku. Tak, żeby wielkość znaków ścieżki zdjęcia wpisanej na stronie, była zgodna z wielkością znaków zapisanego pliku.

Pythonowe funkcje operują na stringach, bez rozeznania w systemie plików.
Chat GPT na począku proponował takie rozwiązanie:

    if os.path.exists(path):
        return os.path.normpath(path)

Po moim komentarzu:

normpath just converts string argument. It doesn't look up the file in filesystem. I want a solution that reads file's case sensitive name.

Wymyślił coś takiego:

import os
import ctypes
from ctypes import wintypes

def get_case_sensitive_path(path):
    kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)

    FILE_FLAG_BACKUP_SEMANTICS = 0x02000000
    FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000

    FILE_SHARE_READ = 1
    OPEN_EXISTING = 3
    FILE_ATTRIBUTE_NORMAL = 0x80

    lpFileName = os.path.abspath(path)
    dwDesiredAccess = 0
    dwShareMode = FILE_SHARE_READ
    dwCreationDisposition = OPEN_EXISTING
    dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT
    hTemplateFile = None

    hFile = kernel32.CreateFileW(
        lpFileName,
        dwDesiredAccess,
        dwShareMode,
        None,
        dwCreationDisposition,
        dwFlagsAndAttributes,
        hTemplateFile
    )

    try:
        result = ctypes.create_unicode_buffer(512)
        kernel32.GetFinalPathNameByHandleW(hFile, result, ctypes.sizeof(result), 0)
        return result.value
    finally:
        kernel32.CloseHandle(hFile)

To działa i na tym poprzestałem.

W czystym Pythonie pewnie mógłbym listować katalog nadrzędny i szukać nazwy pliku, żeby otrzymać nazwę, która jest case sensitive.
A może ktoś ma inną propozycję?

1

Chyba tylko os.listdir(), i znaleźć dopasowanie ręcznie.

1

Wygląda na to że serwis kiedyś stał na windowsie.
Próbowałeś podejść do tego od drugiej strony i po prostu poprawić nazwy plików zamiast skryptu?

  1. Możesz po prostu przelecieć po wszystkich plikach i zmienić ich nazwę na małe litery, to samo zrobić w bazie i po problemie. Nie powinno być żadnych konfliktów bo jeśli faktycznie wcześniej działało to na windowsie to system nie pozwoliłby na utworzenie dwóch plików o tej samej nazwie różniących się tylko wielkością liter.
  2. Możesz też zamontować system plików gdzie masz te pliki jako case-insensitive, wystarczy zrobić volume w fat / ntfs lub włączyć casefold w ext4 https://www.collabora.com/news-and-blog/blog/2020/08/27/using-the-linux-kernel-case-insensitive-feature-in-ext4
0
obscurity napisał(a):

Wygląda na to że serwis kiedyś stał na windowsie.
Próbowałeś podejść do tego od drugiej strony i po prostu poprawić nazwy plików zamiast skryptu?

  1. Możesz po prostu przelecieć po wszystkich plikach i zmienić ich nazwę na małe litery, to samo zrobić w bazie i po problemie. Nie powinno być żadnych konfliktów bo jeśli faktycznie wcześniej działało to na windowsie to system nie pozwoliłby na utworzenie dwóch plików o tej samej nazwie różniących się tylko wielkością liter.
  2. Możesz też zamontować system plików gdzie masz te pliki jako case-insensitive, wystarczy zrobić volume w fat / ntfs lub włączyć casefold w ext4 https://www.collabora.com/news-and-blog/blog/2020/08/27/using-the-linux-kernel-case-insensitive-feature-in-ext4

Niby tak, ale czemu miałby nie poprawić nazw w bazie na takie jakie są faktycznie są w systemie plików?

0

@obscurity: Dobry pomysł ze zmianą nazw plików ;)
I tak jak pobierałem pod Windowsem pliki z FTP, to ewentualne duplikaty case insensitive się nadpisały ;)

Nie ma już tej strony na serwerze, bo usługa hostingu wygasła. Więc nic więcej nie odzyskam.

1 użytkowników online, w tym zalogowanych: 0, gości: 1