Kurejesha data kutoka kwa meza za XtraDB bila faili ya muundo kwa kutumia uchambuzi wa byte-byte wa faili ya ibd

Kurejesha data kutoka kwa meza za XtraDB bila faili ya muundo kwa kutumia uchambuzi wa byte-byte wa faili ya ibd

kabla ya historia

Ilifanyika kwamba seva ilishambuliwa na virusi vya ransomware, ambayo, kwa "ajali ya bahati," iliacha kwa sehemu faili za .ibd (faili za data ghafi za meza za innodb) bila kuguswa, lakini wakati huo huo zilisimbwa kabisa faili za .fpm ( faili za muundo). Katika hali hii, .idb inaweza kugawanywa katika:

  • chini ya urejesho kupitia zana na miongozo ya kawaida. Kwa kesi kama hizo, kuna bora kuwa;
  • jedwali zilizosimbwa kwa kiasi. Mara nyingi hizi ni meza kubwa, ambazo (kama ninavyoelewa) washambuliaji hawakuwa na RAM ya kutosha kwa usimbuaji kamili;
  • Vizuri, meza zilizosimbwa kikamilifu ambazo haziwezi kurejeshwa.

Iliwezekana kuamua ni chaguo gani meza ni za kwa kuifungua tu katika hariri yoyote ya maandishi chini ya usimbuaji unaotaka (kwa upande wangu ni UTF8) na kutazama faili kwa uwepo wa sehemu za maandishi, kwa mfano:

Kurejesha data kutoka kwa meza za XtraDB bila faili ya muundo kwa kutumia uchambuzi wa byte-byte wa faili ya ibd

Pia, mwanzoni mwa faili unaweza kuchunguza idadi kubwa ya ka 0, na virusi vinavyotumia algorithm ya kuzuia kuzuia (ya kawaida) huwaathiri pia.
Kurejesha data kutoka kwa meza za XtraDB bila faili ya muundo kwa kutumia uchambuzi wa byte-byte wa faili ya ibd

Kwa upande wangu, washambuliaji waliacha kamba ya 4-byte (1, 0, 0, 0) mwishoni mwa kila faili iliyosimbwa, ambayo imerahisisha kazi hiyo. Kutafuta faili ambazo hazijaambukizwa, hati ilitosha:

def opened(path):
    files = os.listdir(path)
    for f in files:
        if os.path.isfile(path + f):
            yield path + f

for full_path in opened("C:somepath"):
    file = open(full_path, "rb")
    last_string = ""
    for line in file:
        last_string = line
        file.close()
    if (last_string[len(last_string) -4:len(last_string)]) != (1, 0, 0, 0):
        print(full_path)

Kwa hivyo, iliibuka kupata faili za aina ya kwanza. Ya pili inahusisha kazi nyingi za mwongozo, lakini kile kilichopatikana kilikuwa tayari cha kutosha. Kila kitu kitakuwa sawa, lakini unahitaji kujua muundo sahihi kabisa na (bila shaka) kesi ilitokea kwamba ilibidi nifanye kazi na meza inayobadilika mara kwa mara. Hakuna aliyekumbuka ikiwa aina ya uga ilibadilishwa au safu wima mpya iliongezwa.

Wilds City, kwa bahati mbaya, haikuweza kusaidia katika kesi kama hiyo, ndiyo sababu makala hii inaandikwa.

Fika kwenye uhakika

Kuna muundo wa jedwali kutoka miezi 3 iliyopita ambayo hailingani na ya sasa (labda shamba moja, na ikiwezekana zaidi). Muundo wa Jedwali:

CREATE TABLE `table_1` (
    `id` INT (11),
    `date` DATETIME ,
    `description` TEXT ,
    `id_point` INT (11),
    `id_user` INT (11),
    `date_start` DATETIME ,
    `date_finish` DATETIME ,
    `photo` INT (1),
    `id_client` INT (11),
    `status` INT (1),
    `lead__time` TIME ,
    `sendstatus` TINYINT (4)
); 

katika kesi hii, unahitaji kuchimba:

  • id_point int(11);
  • id_user int(11);
  • date_start DATETIME;
  • date_finish DATETIME.

Kwa ajili ya kurejesha, uchambuzi wa byte-byte wa faili ya .ibd hutumiwa, ikifuatiwa na kuwageuza kuwa fomu inayoweza kusomeka zaidi. Kwa kuwa ili kupata kile tunachohitaji, tunahitaji tu kuchambua aina za data kama vile int na datatime, makala itaelezea wao tu, lakini wakati mwingine tutarejelea aina nyingine za data, ambazo zinaweza kusaidia katika matukio mengine sawa.

Tatizo 1: sehemu zilizo na aina DATETIME na TEXT zilikuwa na maadili NULL, na zimerukwa tu kwenye faili, kwa sababu ya hii, haikuwezekana kuamua muundo wa kurejesha katika kesi yangu. Katika safu wima mpya, thamani chaguo-msingi ilibatilishwa, na sehemu ya muamala inaweza kupotea kwa sababu ya mpangilio innodb_flush_log_at_trx_commit = 0, kwa hivyo muda wa ziada ungetumika kubainisha muundo.

Tatizo 2: inapaswa kuzingatiwa kuwa safu mlalo zilizofutwa kupitia DELETE zote zitakuwa kwenye faili ya ibd, lakini kwa ALTER TABLE muundo wao hautasasishwa. Matokeo yake, muundo wa data unaweza kutofautiana kutoka mwanzo wa faili hadi mwisho wake. Ikiwa mara nyingi hutumia OPTIMIZE TABLE, basi kuna uwezekano wa kukutana na tatizo kama hilo.

Makini, toleo la DBMS huathiri jinsi data inavyohifadhiwa, na mfano huu unaweza usifanye kazi kwa matoleo mengine makuu. Katika kesi yangu, toleo la windows la mariadb 10.1.24 lilitumiwa. Pia, ingawa katika mariadb unafanya kazi na jedwali za InnoDB, kwa kweli ziko XtraDB, ambayo haijumuishi utumiaji wa njia na InnoDB mysql.

Uchambuzi wa faili

Katika python, aina ya data baiti() huonyesha data ya Unicode badala ya seti ya kawaida ya nambari. Ingawa unaweza kuona faili katika fomu hii, kwa urahisi unaweza kubadilisha baiti kuwa fomu ya nambari kwa kubadilisha safu ya baiti kuwa safu ya kawaida (orodha(mfano_byte_array)). Kwa hali yoyote, njia zote mbili zinafaa kwa uchambuzi.

Baada ya kuangalia faili kadhaa za ibd, unaweza kupata zifuatazo:

Kurejesha data kutoka kwa meza za XtraDB bila faili ya muundo kwa kutumia uchambuzi wa byte-byte wa faili ya ibd

Zaidi ya hayo, ukigawanya faili kwa maneno haya muhimu, utapata data nyingi hata. Tutatumia infimum kama kigawanyo.

table = table.split("infimum".encode())

Uchunguzi wa kuvutia: kwa meza zilizo na kiasi kidogo cha data, kati ya infimum na supremum kuna pointer kwa idadi ya safu katika block.

Kurejesha data kutoka kwa meza za XtraDB bila faili ya muundo kwa kutumia uchambuzi wa byte-byte wa faili ya ibd - Jedwali la majaribio na safu ya 1

Kurejesha data kutoka kwa meza za XtraDB bila faili ya muundo kwa kutumia uchambuzi wa byte-byte wa faili ya ibd - Jedwali la mtihani na safu 2

Jedwali la safu mlalo[0] linaweza kurukwa. Baada ya kuiangalia, bado sikuweza kupata data ya jedwali mbichi. Uwezekano mkubwa zaidi, kizuizi hiki kinatumika kuhifadhi faharisi na funguo.
Kuanzia na jedwali[1] na kuitafsiri katika safu ya nambari, tayari unaweza kugundua mifumo kadhaa, ambayo ni:

Kurejesha data kutoka kwa meza za XtraDB bila faili ya muundo kwa kutumia uchambuzi wa byte-byte wa faili ya ibd

Hizi ni maadili ya int yaliyohifadhiwa kwenye mfuatano. Byte ya kwanza inaonyesha ikiwa nambari ni chanya au hasi. Katika kesi yangu, nambari zote ni chanya. Kutoka kwa ka 3 zilizobaki, unaweza kuamua nambari kwa kutumia kazi ifuatayo. Hati:

def find_int(val: str):  # example '128, 1, 2, 3'
    val = [int(v) for v in  val.split(", ")]
    result_int = val[1]*256**2 + val[2]*256*1 + val[3]
    return result_int

Kwa mfano, 128, 0, 0, 1 = 1Au 128, 0, 75, 108 = 19308.
Jedwali lilikuwa na ufunguo msingi na nyongeza ya kiotomatiki, na inaweza pia kupatikana hapa

Kurejesha data kutoka kwa meza za XtraDB bila faili ya muundo kwa kutumia uchambuzi wa byte-byte wa faili ya ibd

Baada ya kulinganisha data kutoka kwa majedwali ya majaribio, ilibainika kuwa kitu cha DATETIME kina baiti 5 na kilianza na 153 (uwezekano mkubwa zaidi unaonyesha vipindi vya kila mwaka). Kwa kuwa safu ya DATTIME ni '1000-01-01' hadi '9999-12-31', nadhani idadi ya ka inaweza kutofautiana, lakini kwa upande wangu, data iko katika kipindi cha 2016 hadi 2019, kwa hivyo tutafikiria. kwamba ka 5 za kutosha.

Kuamua wakati bila sekunde, kazi zifuatazo ziliandikwa. Hati:

day_ = lambda x: x % 64 // 2  # {x,x,X,x,x }

def hour_(x1, x2):  # {x,x,X1,X2,x}
    if x1 % 2 == 0:
        return x2 // 16
    elif x1 % 2 == 1:
        return x2 // 16 + 16
    else:
        raise ValueError

min_ = lambda x1, x2: (x1 % 16) * 4 + (x2 // 64)  # {x,x,x,X1,X2}

Haikuwezekana kuandika kazi ya kufanya kazi kwa mwaka na mwezi, kwa hivyo ilinibidi kuihack. Hati:

ym_list = {'2016, 1': '153, 152, 64', '2016, 2': '153, 152, 128', 
           '2016, 3': '153, 152, 192', '2016, 4': '153, 153, 0',
           '2016, 5': '153, 153, 64', '2016, 6': '153, 153, 128', 
           '2016, 7': '153, 153, 192', '2016, 8': '153, 154, 0', 
           '2016, 9': '153, 154, 64', '2016, 10': '153, 154, 128', 
           '2016, 11': '153, 154, 192', '2016, 12': '153, 155, 0',
           '2017, 1': '153, 155, 128', '2017, 2': '153, 155, 192', 
           '2017, 3': '153, 156, 0', '2017, 4': '153, 156, 64',
           '2017, 5': '153, 156, 128', '2017, 6': '153, 156, 192',
           '2017, 7': '153, 157, 0', '2017, 8': '153, 157, 64',
           '2017, 9': '153, 157, 128', '2017, 10': '153, 157, 192', 
           '2017, 11': '153, 158, 0', '2017, 12': '153, 158, 64', 
           '2018, 1': '153, 158, 192', '2018, 2': '153, 159, 0',
           '2018, 3': '153, 159, 64', '2018, 4': '153, 159, 128', 
           '2018, 5': '153, 159, 192', '2018, 6': '153, 160, 0',
           '2018, 7': '153, 160, 64', '2018, 8': '153, 160, 128',
           '2018, 9': '153, 160, 192', '2018, 10': '153, 161, 0', 
           '2018, 11': '153, 161, 64', '2018, 12': '153, 161, 128',
           '2019, 1': '153, 162, 0', '2019, 2': '153, 162, 64', 
           '2019, 3': '153, 162, 128', '2019, 4': '153, 162, 192', 
           '2019, 5': '153, 163, 0', '2019, 6': '153, 163, 64',
           '2019, 7': '153, 163, 128', '2019, 8': '153, 163, 192',
           '2019, 9': '153, 164, 0', '2019, 10': '153, 164, 64', 
           '2019, 11': '153, 164, 128', '2019, 12': '153, 164, 192',
           '2020, 1': '153, 165, 64', '2020, 2': '153, 165, 128',
           '2020, 3': '153, 165, 192','2020, 4': '153, 166, 0', 
           '2020, 5': '153, 166, 64', '2020, 6': '153, 1, 128',
           '2020, 7': '153, 166, 192', '2020, 8': '153, 167, 0', 
           '2020, 9': '153, 167, 64','2020, 10': '153, 167, 128',
           '2020, 11': '153, 167, 192', '2020, 12': '153, 168, 0'}

def year_month(x1, x2):  # {x,X,X,x,x }

    for key, value in ym_list.items():
        key = [int(k) for k in key.replace("'", "").split(", ")]
        value = [int(v) for v in value.split(", ")]
        if x1 == value[1] and x2 // 64 == value[2] // 64:
            return key
    return 0, 0

Nina hakika kwamba ikiwa unatumia kiasi cha muda, kutokuelewana huku kunaweza kusahihishwa.
Ifuatayo, chaguo la kukokotoa linalorudisha kipengee cha tarehe kutoka kwa mfuatano. Hati:

def find_data_time(val:str):
    val = [int(v) for v in val.split(", ")]
    day = day_(val[2])
    hour = hour_(val[2], val[3])
    minutes = min_(val[3], val[4])
    year, month = year_month(val[1], val[2])
    return datetime(year, month, day, hour, minutes)

Imedhibitiwa kugundua maadili yanayorudiwa mara kwa mara kutoka kwa int, int, wakati wa tarehe, wakati Kurejesha data kutoka kwa meza za XtraDB bila faili ya muundo kwa kutumia uchambuzi wa byte-byte wa faili ya ibd, inaonekana kama hiki ndicho unachohitaji. Aidha, mlolongo huo haurudiwi mara mbili kwa kila mstari.

Kutumia usemi wa kawaida, tunapata data inayofaa:

fined = re.findall(r'128, d*, d*, d*, 128, d*, d*, d*, 153, 1[6,5,4,3]d, d*, d*, d*, 153, 1[6,5,4,3]d, d*, d*, d*', int_array)

Tafadhali kumbuka kuwa unapotafuta kutumia usemi huu, haitawezekana kuamua maadili NULL katika sehemu zinazohitajika, lakini kwa upande wangu hii sio muhimu. Kisha tunapitia kile tulichopata kwenye kitanzi. Hati:

result = []
for val in fined:
    pre_result = []
    bd_int  = re.findall(r"128, d*, d*, d*", val)
    bd_date= re.findall(r"(153, 1[6,5,4,3]d, d*, d*, d*)", val)
    for it in bd_int:
        pre_result.append(find_int(bd_int[it]))
    for bd in bd_date:
        pre_result.append(find_data_time(bd))
    result.append(pre_result)

Kwa kweli, hiyo ndiyo yote, data kutoka kwa safu ya matokeo ndio data tunayohitaji. ###PS.###
Ninaelewa kuwa njia hii haifai kwa kila mtu, lakini lengo kuu la makala ni kuharakisha hatua badala ya kutatua matatizo yako yote. Nadhani suluhisho sahihi zaidi itakuwa kuanza kusoma nambari ya chanzo mwenyewe mariadb, lakini kutokana na muda mdogo, njia ya sasa ilionekana kuwa ya haraka zaidi.

Katika baadhi ya matukio, baada ya kuchambua faili, utaweza kuamua muundo wa takriban na kurejesha kwa kutumia mojawapo ya mbinu za kawaida kutoka kwa viungo hapo juu. Hii itakuwa sahihi zaidi na kusababisha matatizo machache.

Chanzo: mapenzi.com

Kuongeza maoni