Vakar darbe pabaigiau vieną darbelį ir prieš dėdamas jį į revizijų kontrolę, nusprendžiau pabūti doras ir padaryti tai, ką mes vadinam TMR: Total Massive Rebuild. Tai veiksmas, kai perkompiliuoji visai visą produktą, kad įsitikinti, kad niekam nieko nesugadinai.
Nu cvs up
, nu make clean
, nu make all
. Įprasti dalykai. Kompiliuojasi.
Tik kompiliuojasi neilgai, sustoja, nes sugriūna kažkuris unit testas. Galvoju, WTF? Bet aiškintis neturėjau laiko, tai užsiėmiau tuo šiandien.
Gana greitai išsiaiškinu kodėl griūna testas -- kolega neseniai padarė pakeitimą, visai gerą pakeitimą, dėl kurio šita problema ir turi išlįsti, o ne tyliai likti praignoruota. Viskas lyg ir tvarkoj. Bet vienas dalykas netvarkoj -- o kodėl man išlenda šita klaida, o kitiems ne?
Padebuginus paaiškėja, kad nesuveikia štai toks kodas:
mkdir ("%TEMP%/sub1/sub2/sub3/.../sub28/sub29");
(Tik vietoj %TEMP%
ten buvo tikras kelias į temp direktoriją: C:\Users\Vytautas.Saltenis\AppData\Ir\Dar\Kažkas\Nepamenu\Kas\
. Nu ir, aišku, vietoj daugtaškio visi trūkstami sub-sub-sub.)
Įtarimas aiškus -- kažkodėl viršija MAX_PATH
. Betgi nusikopijuojam tą eilutę, pamatuojam jos ilgį ir matom, kad ne, neviršija. Jos ilgis 248. Va šitoj vietoj prasideda kondicija “O-ba…”.
Pirma mintis: gal aš neteisingai atsimenu kiek yra MAX_PATH
? Pasitikrinu, 260. Reiškia teisingai, ne tas…
Tada tikrinam klaidos kodą. errno
po mkdir()
būna 2, kas yra ENOENT
, ką dokumentacija iškilmingai išaiškina: “Path was not found.”. Blet. Koks dar not found? Aš gi sukurti bandau!
Gūglinam kaip ant Vindauso padarytas mkdir()
. Randam, kad ten jis yra plonas wrapperis ant CreateDirectory()
-- “gerai bent tiek, o ne atskira realizacija”, spėju pagalvoti.
OK, tad kaipgi galima priversti CreateDirectory()
nesuveikti? Ten yra kažkoks antras parametras, kažkas su security, gal ten kažkas ne taip? Nu, debuginam visaip kaip išsijuosę, ir žiūrim, kad mkdir()
padarytas maždaug va taip:
int mkdir (char *path)
{
return CreateDirectory (path, NULL);
}
Blyn. Nu irgi nėra kam nesuveikti… Nebent tas NULL
20 metų veikė, o dabar neveikia. Vėjai.
Bet čia eiga pasisuka link atomazgos, prieinama prie <a href="http://msdn.microsoft.com/en-us/library/aa363855(VS.85).aspx">CreateDirectory()</a>
dokumentacijos. Paskaitom prierašą prie pirmo parametro, ir liekam “в охуе”:
“There is a default string size limit for paths of 248 characters. This limit is related to how the CreateDirectory function parses paths.”
Bingo! Pasirodo, visgi susidūriau su limitu, pasiaiškinam kodėl kiti nesusidūrė, pataisom ir ilgai ir laimingai gyvenam. Boring.
The fun part! Kuo galvojo tas senovinis Microsoft darbuotojas, kuris parašė CreateDirectory()
? Ar jis išvis galvojo? Ne, nu rimtai. Gaunasi taip: mūsų sistemoje apribojimas kelio ilgiui yra 260, bet aš chujovas programuotojas, dėl to nemoku suprogramuoti taip, kad būčiau suderinamas su likusia sistema ir padarysiu 248 ir dokumentacijoje parašysiu, kad aš chujovas programuotojas. Rimtai, taip išeina. Paskaitykit dar kartą citatą iš dokumentacijos:
“There is a default string size limit for paths of 248 characters. This limit is related to how impaired was the original author of CreateDirectory.”
Pakalbam apie tai su kolegomis, pažvengiam, aptariam, paspėliojam kodėl 248, o ne 246, kodėl išvis yra toks MAX_PATH
ir kodėl jis 260, o ne 256 ir pan… Linksmiausia išsakyta versija tokia: o nefig tau kurti direktorijos, į kurią paskui netilps 8.3 failas! Dėl to ir MAX_PATH - 12 = 248
. Skamba įtikinamai ;-)
Akylesni skaitytojai gal pastebėjo ir iki šiol nesupranta kodėl gi man neveikė? Juk mano kelio ilgis buvo 248, ir funkcija priima 248. Turi veikti. Cha cha! Nieko jūs nesuprantat! Chujovą funkciją reikia ne tik chujovai suprogramuoti, ją paskui dar reikia ir chujovai dokumentuoti! Kitaip gausis tik pusiau chujova funkcija. Iš tikro jinai veikia su keliais iki 247 simbolių ilgio imtinai, o dokumentatorius parašė kokio dydžio buferis ten viduje naudojamas keliui kartu su terminuojančiu nuliu laikyti.
Atrodytų, tokia vat nuotaikinga istorija. Ir maniau, kad toliau jau nėra kur, kad čia viršūnė. Nope, naivu. Betvarkydamas mūsų kodą, užklydau į kitos įdomios funkcijos <a href="http://msdn.microsoft.com/en-us/library/aa364991.aspx">GetTempFileName()</a>
dokumentaciją. Skaitom pirmo parametro aprašymą:
“The directory path for the file name. […] The string cannot be longer than MAX_PATH–14 characters or GetTempFileName will fail. If this parameter is NULL, the function fails.”
Uch ty! Štai jums ir 246! Man dabar baisu į gūglą įvesti “MAX_PATH - 17”, bijau, kad ką nors suras :-)
Beje, plika akim tai sunkiai įžiūrima, bet ten dokumentacijoj parašyta ne “MAX_PATH-14”. Rimtai, nejuokauju. Ten ne minusas, ten tipografinis brūkšnys, “En dash” vadinasi. Ir jeigu nukopijuosi tą daiktą į kodą, gausi keistų pranešimų nuo kompiliatoriaus, versijų kontrolės sistemos ir kitų “suinteresuotų šalių”.
Va taip vat. Pyzdėc, gerbiamieji Redmondo programuotojai. Pyz-dėc.
jrs0ul
2009-04-24 08:54
lol.
Kažkaip galvodavau, kad MAX_PATH yra lygus 256. O kam gali reikėt tokio ilgo patho ? Btw kam reikia daryti kažką windowsams jei taip nepatinka :) ?