1 // streaming file system (virtual)
2 {$MODE DELPHI}
3 {.$R-}
4 {.$DEFINE SFS_VOLDEBUG}
7 interface
9 uses
13 type
22 public
24 fPath: TSFSString; // ðàçäåëèòåëè êàòàëîãîâ -- "/"; êîðåíü íèêàê íå îáîçíà÷åí, åñëè íå ïóñòîå, îáÿçàíî çàâåðøàåòñÿ "/"
37 // âèðòóàëüíàÿ ôàéëîâàÿ ñèñòåìà. ÒÎËÜÊÎ ÄËß ×ÒÅÍÈß!
38 // òîì ÍÅ ÄÎËÆÅÍ óáèâàòüñÿ íèêàê èíà÷å, ÷åì ïðè ïîìîùè ôàáðèêè!
40 protected
46 // ïðèøèáèòü âñå ñòðóêòóðû.
47 // íå äîëæíà ïàäàòü, åñëè å¸ âûçûâàþò íåñêîëüêî ðàç.
50 // âûçûâàåòñÿ èç DoDirectoryRead() äëÿ çàïîëíåíèÿ ñïèñêà ôàéëîâ.
51 // ñ÷èòàåòñÿ, ÷òî âñå ìàãèêè óæå ïðîâåðåíû è ôàéë òî÷íî íàø.
52 // fFileName, fFileStream óæå óñòàíîâëåíû, fFiles ñîçäàí,
53 // â í¸ì, ñêîðåå âñåãî, íèêîãî íåò.
54 // ïîçèöèÿ ïîòîêà -- òà, ÷òî îñòàâèëà ôàáðèêà.
55 // ïðè îøèáêàõ êèäàòü èñêëþ÷åíèå, òîãäà òîì áóäåò ïðèáèò ôàáðèêîé.
56 // ðàçäåëèòåëè ïóòåé äîëæíû áûòü òîëüêî "/", êîðíåâîé "/" äîëæåí
57 // áûòü îïóùåí, ïóòè (åñëè íå ïóñòûå) äîëæíû çàâåðøàòüñÿ "/"!
58 // fName äîëæíî ñîäåðæàòü òîëüêî èìÿ, fPath -- òîëüêî ïóòü.
59 // â ïðèíöèïå, îá ýòîì ïîçàáîòèòñÿ DoDirectoryRead(), íî çà÷åì
60 // äàâàòü åìó ëèøíþþ ðàáîòó?
63 // íàéòè ôàéë, âåðíóòü åãî èíäåêñ â fFiles.
64 // ýòà ïðîöåäóðà ìîæåò ìåíÿòü fFiles!
65 // fPath -- â ïðàâèëüíîé ôîðìå, ñ "/", êîðíåâîé "/" óáèò, ôèíàëüíûé äîáàâëåí.
66 // åñëè ôàéë íå íàéäåí, âåðíóòü -1.
69 // âîçâðàùàåò êîëè÷åñòâî ôàéëîâ â fFiles
72 // âîçâðàùàåò ôàéë ñ èíäåêñîì index.
73 // ìîæåò âîçâðàùàòü NIL.
74 // íèêàêèõ ïàäåíèé íà íåïðàâèëüíûå èíäåêñû!
79 public
80 // pSt íå îáÿçàòåëüíî çàïîìèíàòü, åñëè îí íå íóæåí.
82 // fFileStream óíè÷òîæàòü íåëüçÿ, åñëè îí ðàâåí ïàðàìåòðó pSt êîíñòðóêòîðà.
85 // âûçûâàåò ReadDirectory().
86 // ýòà ïðîöåäóðà ñàìà ðàçáåð¸òñÿ ñ äóáëèêàòàìè èì¸í: ïîäîáàâëÿåò â
87 // êîíåö èì¸í-äóáëèêàòîâ ïîä÷¸ðêèâàíèå è äåñÿòè÷íûé íîìåð.
88 // òàêæå îíà íîðìàëèçóåò âèä èì¸í.
91 // ïðè îøèáêàõ êèäàòüñÿ èñêëþ÷åíèÿìè.
94 // åñëè íå ñìîãëî îòêóïîðèòü ôàéëî (èëè åù¸ ãäå îøèáëîñü), çàøâûðí¸ò èñêëþ÷åíèå.
98 // ìîæåò âîçâðàùàòü NIL.
99 // íèêàêèõ ïàäåíèé íà íåïðàâèëüíûå èíäåêñû!
103 // ôàáðèêà òîìîâ. âñå SFS ïðè ñòàðòå äîáàâëÿþò ñâîè ôàáðèêè.
104 // áëàãîäàðÿ ýòîìó ìîæíî ñîçäàâàòü ðàçíûå âñÿêèå SFS ñòàíäàðòíûì
105 // âûçîâîì ñòàíäàðòíîé ïðîöåäóðû.
106 // ôàáðèêà ÍÅ ÄÎËÆÍÀ óáèâàòüñÿ íèêàê èíà÷å, ÷åì ïðè ïîìîùè âûçîâà
107 // SFSUnregisterVolumeFactory()! ýòî ãàðàíòèðóåò, ÷òî äâèæîê
108 // ïåðåä ðàññòðåëîì îòäàñò åé âñå å¸ òîìà.
110 public
111 // åñëè äîáàâëÿåì ôàéë äàííûõ ôàéë ñ èìåíåì òèïà "zip:....", òî
112 // SFS èçâëå÷¸ò ýòî "zip" è ïåðåäàñò â ñèþ ôóíêöèþ.
113 // åæåëè ôóíêöèÿ âåðí¸ò ïðàâäó, òî SFS âûçîâåò Produce äëÿ äàííîãî
114 // ôàéëà. åñëè íè îäíà ôàáðèêà ïðåôèêñ íå ïðèçíàåò, òî ôàéë íå îòêðîþò.
115 // èñïîëüçóåòñÿ äëÿ ñêèïàíèÿ àâòîäåòåêòà.
116 // SFS ÍÅ Ñ×ÈÒÀÅÒ ÏÐÅÔÈÊÑÎÌ ÑÒÐÎÊÓ ÊÎÐÎ×Å ÒÐ¨Õ ÑÈÌÂÎËÎÂ!
118 // ïðîâåðÿåò, ìîæåò ëè ôàáðèêà ñäåëàòü òîì äëÿ äàííîãî ôàéëà.
119 // st -- îòêðûòûé äëÿ ÷òåíèÿ ôàéëîâé ïîòîê. óêàçàòåëü ÷òåíèÿ ñòîèò â íà÷àëå.
120 // ýòîò ïîòîê íåëüçÿ çàêðûâàòü!
121 // prefix: òî, ÷òî áûëî ïåðåäàíî â IsMyVolumePrefix() èëè ''.
122 // èñêëþ÷åíèå ñ÷èòàåòñÿ îøèáêîé, âîçâðàò NIL ñ÷èòàåòñÿ îøèáêîé.
123 function Produce (const prefix, fileName: TSFSString; st: TStream): TSFSVolume; virtual; abstract;
124 // êîãäà òîì áîëüøå íå íóæåí, îí áóäåò îòäàí ôàáðèêå íà ïåðåðàáîòêó.
125 // äàëåå äâèæîê íå áóäåò þçàòü ñåé òîì.
129 // "èòåðàòîð", âîçâðàùàåìûé SFSFileList()
131 protected
137 public
143 // ïðè íåïðàâèëüíîì èíäåêñå ìîë÷à âåðí¸ò NIL.
144 // ïðè ïðàâèëüíîì òîæå ìîæåò âåðíóòü NIL!
145 // î÷åíü íå ñîâåòóþ ìåíÿòü ñîäåðæèìîå ïîëó÷åííîãî êëàññà.
146 // êîíå÷íî, ÿ ìîã áû âîçâðàùàòü íîâóþ ñòðóêòóðó èëè íå÷òî ïîõîæåå,
147 // íî áëèí, åñëè òû èäèîò è íå óìååøü äàæå êîììåíòû ÷èòàòü, òî
148 // êàêîãî òû âîîáùå â ïðîãðàììèíã ïîëåç?
154 // ýòà ôóíêöèÿ àâòîìàòè÷åñêè ïðèáü¸ò factory.
157 // äîáàâèòü ñáîðíèê â ïîñòîÿííûé ñïèñîê.
158 // åñëè ñáîðíèê ñ òàêèì èìåíåì óæå îòêðûò, òî íå îòêðûâàåò åãî ïîâòîðíî.
159 // íèêîãäà íå êèäàåò èñêëþ÷åíèé.
160 // top: äîáàâèòü â íà÷àëî ñïèñêà ïîèñêà.
161 // âåðí¸ò ëîæü ïðè îøèáêå.
162 // ñïîñîáíî îòêðûâàòü ñáîðíèêè â ñáîðíèêàõ ïðè ïîìîùè êðóòûõ èì¸í a-la:
163 // "zip:pack0::pack:pack1::wad2:pack2".
164 // â äàëüíåéøåì ñëåäóåò îáðàùàòüñÿ ê ñáîðíèêó êàê "pack2::xxx".
165 // èëè ìîæíî íàïèñàòü:
166 // "zip:pack0::pack:pack1::wad2:pack2|datafile".
167 // è îáðàùàòüñÿ êàê "datafile::xxx".
168 // "||" ïðåîáðàçóþòñÿ â ïðîñòîé "|" è ðàçäåëèòåëåì íå ñ÷èòàþòñÿ.
169 // ïðèíèìàåòñÿ âî âíèìàíèå òîëüêî ïîñëåäíÿÿ òðóáà.
172 // äîáàâèòü ñáîðíèê âðåìåííî
175 // äîáàâèòü â ïîñòîÿííûé ñïèñîê ñáîðíèê èç ïîòîêà ds.
176 // åñëè âîçâðàùàåò èñòèíó, òî SFS ñòàíîâèòñÿ âëÿäåëüöåì ïîòîêà ds è ñàìà
177 // óãðîáèò ñåé ïîòîê ïî íåîáõîäèìîñòè.
178 // virtualName ñòàíîâèòñÿ èìåíåì ñáîðíèêà äëÿ îïåðàöèè îòêðûòèÿ ôàéëà òèïà
179 // "packfile:file.ext".
180 // åñëè êàêîé-íèáóäü ñáîðíèê ñ èìåíåì virtualName óæå îòêðûò, âåðí¸ò false.
181 // íèêîãäà íå êèäàåò èñêëþ÷åíèé.
182 // top: äîáàâèòü â íà÷àëî ñïèñêà ïîèñêà.
183 // âåðí¸ò ëîæü ïðè îøèáêå.
184 // îòêðûâàåò ñáîðíèê èç ïîòîêà. dataFileName -- ÂÈÐÒÓÀËÜÍÎÅ èìÿ.
185 // ò.å. íà ñàìîì äåëå òàêîãî ôàéëà ìîæåò è íå áûòü íà äèñêå.
186 function SFSAddSubDataFile (const virtualName: TSFSString; ds: TStream; top: Boolean=false): Boolean;
188 // øâûðÿåòñÿ èñêëþ÷åíèÿìè.
189 // åñëè fName íå èìååò óêàçàíèÿ íà ôàéë äàííûõ (ýòî òî, ÷òî îòäåëåíî îò
190 // îñòàëüíîãî èìåíè äâîåòî÷èåì), òî èùåì ñíà÷àëà ïî âñåì çàðåãèñòðèðîâàííûì
191 // ôàéëàì äàííûõ, ïîòîì â òåêóùåì êàòàëîãå, ïîòîì â êàòàëîãå, îòêóäà ñòàðòîâàëè.
192 // åñëè íè÷åãî íå íàøëè, êèäàåì èñêëþ÷åíèå.
195 // ïðè îøèáêå -- NIL, è íèêàêèõ èñêëþ÷åíèé.
198 // âîçâðàùàåò NIL ïðè îøèáêå.
199 // ïîñëå èñïîëüçîâàíèÿ, íàòóðàëüíî, èòåðàòîð íàäî ãðîõíóòü %-)
202 // çàïðåòèòü îñâîáîæäåíèå âðåìåííûõ òîìîâ (ìîæíî âûçûâàòü ðåêóðñèâíî)
205 // ðàçðåøèòü îñâîáîæäåíèå âðåìåííûõ òîìîâ (ìîæíî âûçûâàòü ðåêóðñèâíî)
208 // for completeness sake
213 // ðàçîáðàòü òîëñòîå èìÿ ôàéëà, âåðíóòü âèðòóàëüíîå èìÿ ïîñëåäíåãî ñïèñêà
214 // èëè ïóñòóþ ñòîðîêó, åñëè ñïèñêîâ íå áûëî.
217 // Wildcard matching
218 // this code is meant to allow wildcard pattern matches. tt is VERY useful
219 // for matching filename wildcard patterns. tt allows unix grep-like pattern
220 // comparisons, for instance:
221 //
222 // ? Matches any single characer
223 // + Matches any single characer or nothing
224 // * Matches any number of contiguous characters
225 // [abc] Matches a or b or c at that position
226 // [!abc] Matches anything but a or b or c at that position
227 // [a-e] Matches a through e at that position
228 //
229 // 'ma?ch.*' -Would match match.exe, mavch.dat, march.on, etc
230 // 'this [e-n]s a [!zy]est' -Would match 'this is a test', but would
231 // not match 'this as a yest'
232 //
238 var
239 // ïðàâäà: ðàçðåøåíî èñêàòü ôàéëî íå òîëüêî â ôàéëàõ äàííûõ, íî è íà äèñêå.
241 // ïðàâäà: åñëè ôàéë íå ïðåôèêñîâàí, òî ñíà÷àëà èùåì ôàéëî íà äèñêå,
242 // ïîòîì â ôàéëàõ äàííûõ.
244 // ïðàâäà: äàæå äëÿ ïðåôèêñîâàíûõ ôàéëîâ ñíà÷àëà ïðîñìîòðèì äèñê
245 // (åñëè óñòàíîâëåí ôëàæîê sfsDiskFirst è sfsDiskEnabled).
247 // ñïèñîê äèñêîâûõ êàòàëîãîâ äëÿ ïîèñêà ôàéëà. åñëè ïóñò -- èùåì òîëüêî â
248 // òåêóùåì. êàòàëîãè ðàçäåëÿþòñÿ òðóáîé ("|").
249 // <currentdir> çàìåíÿåòñÿ íà òåêóùèé êàòàëîã (ñ çàâåðøàþùèì "/"),
250 // <exedir> çàìåíÿåòñÿ íà êàòàëîã, ãäå ñèäèò .EXE (ñ çàâåðøàþùèì "/").
254 implementation
256 uses
260 const
261 // character defines
273 begin
274 result :=
282 function MatchMask (const pattern: TSFSString; p, pend: Integer; const text: TSFSString; t, tend: Integer): Boolean;
283 var
287 begin
288 // sanity checks
294 begin
296 begin
297 // no more text. check if there's no more chars in pattern (except "*" & "+")
302 exit;
305 WILD_CHAR_SINGLE: ;
306 WILD_CHAR_ESCAPE:
307 begin
312 WILD_CHAR_RANGE_OPEN:
313 begin
321 repeat
327 begin
331 begin
333 end
335 end
340 // skip the rest or the range
344 WILD_CHAR_SINGLE_OR_NONE:
345 begin
349 exit;
351 WILD_CHAR_MULTI:
352 begin
356 begin
360 exit;
371 begin
378 var
380 begin
386 begin
388 begin
390 begin
397 begin
407 type
413 fPermanent: Boolean; // èñòèíà -- íå áóäåò óãðîáëåíà, åñëè íå îñòàíåòñÿ íè îäíîãî îòêðûòîãî òîìà
414 // èñòèíà -- ýòîò òîì áûë ñîçäàí èç ïîòîêà è íå èìååò äèñêîâîãî ôàéëà, ïîòîìó ôàáðèêå áóäåò ïåðåäàíî íå èìÿ ñáîðíèêà, à ïóñòàÿ ñòðîêà
422 protected
425 public
431 var
438 var
442 begin
443 // collect garbage
446 begin
450 begin
451 // this volume probably can be removed
455 begin
457 begin
465 begin
466 {$IFDEF SFS_VOLDEBUG}writeln('000: destroying volume "', TVolumeInfo(volumes[f]).fPackName, '"');{$ENDIF}
470 continue;
478 begin
483 begin
486 begin
493 // ðàçáèòü èìÿ ôàéëà íà ÷àñòè: ïðåôèêñ ôàéëîâîé ñèñòåìû, èìÿ ôàéëà äàííûõ,
494 // ñîáñòâåííî èìÿ ôàéëà
495 // èìÿ âûãëÿäèò êàê:
496 // (("sfspfx:")?"datafile::")*"filename"
498 var
500 begin
503 begin
508 else
509 begin
515 // ñàéäýôôåêò: âûðåçàåò âèðòóàëüíîå èìÿ èç dataFile.
517 var
519 begin
522 begin
525 begin
527 else
528 begin
531 break;
538 // ðàçáèòü èìÿ ñáîðíèêà íà ÷àñòè: ïðåôèêñ ôàéëîâîé ñèñòåìû, èìÿ ôàéëà äàííûõ,
539 // âèðòóàëüíîå èìÿ. åñëè âèðòóàëüíîãî èìåíè íå äàíî, îíî áóäåò ðàâíî dataFile.
540 // èìÿ âûãëÿäèò êàê:
541 // [sfspfx:]datafile[|virtname]
542 // åñëè ïåðåä äâîåòî÷èåì ìåíüøå òð¸õ áóêâ, òî ýòî ñ÷èòàåòñÿ íå ïðåôèêñîì,
543 // à èìåíåì äèñêà.
545 var
547 begin
550 else
551 begin
558 // íàéòè ïðîèçâîäèòåëÿ äëÿ ýòîãî ôàéëà (åñëè ôàéë óæå îòêðûò).
559 // onlyPerm: òîëüêî "ïîñòîÿííûå" ïðîèçâîäèòåëè.
561 var
564 begin
567 begin
569 begin
572 begin
574 begin
576 exit;
585 // íàéòè èíôó äëÿ ýòîãî òîìà.
586 // õîðîøåå èìÿ, ïðàâäà? %-)
588 begin
591 begin
593 begin
601 // adds '/' too
603 var
605 begin
609 begin
611 begin
613 continue;
616 begin
618 end
619 else
620 begin
629 var
631 begin
634 begin
636 begin
637 // avoid unnecessary string changes
644 var
647 begin
649 repeat
657 { TVolumeInfo }
659 var
662 begin
669 // òèïà ìóñîðîñáîðíèê: åñëè íàø ïîòîê áîëåå íèêåì íå þçàåòñÿ, òî óãðîáèòü åãî íàôèã
671 begin
675 begin
677 begin
680 begin
693 { TOwnedPartialStream }
696 begin
703 var
705 begin
708 begin
711 begin
714 begin
715 {$IFDEF SFS_VOLDEBUG}writeln('001: destroying volume "', TVolumeInfo(volumes[f]).fPackName, '"');{$ENDIF}
723 { TSFSFileInfo }
725 begin
736 begin
742 { TSFSVolume }
744 begin
753 begin
757 var
761 begin
768 begin
770 // normalize name & path
777 begin
778 // split path and name
791 begin
798 begin
804 begin
806 else
807 begin
810 begin
813 begin
823 begin
828 begin
830 else
831 begin
838 var
841 begin
843 // normalize name, find split position
847 begin
860 { TSFSFileList }
862 var
864 begin
874 var
876 begin
881 // óáü¸ì çàïèñü, åñëè îíà âðåìåííàÿ, è â íåé íåò áîëüøå íè÷åãî îòêðûòîãî
882 if (gcdisabled = 0) and not TVolumeInfo(volumes[f]).fPermanent and (TVolumeInfo(volumes[f]).fOpenedFilesCount < 1) then
883 begin
884 {$IFDEF SFS_VOLDEBUG}writeln('002: destroying volume "', TVolumeInfo(volumes[f]).fPackName, '"');{$ENDIF}
891 begin
896 begin
903 var
905 begin
914 var
917 begin
922 begin
930 function SFSAddDataFileEx (dataFileName: TSFSString; ds: TStream; top, permanent: Integer): Integer;
931 // dataFileName ìîæåò èìåòü ïðåôèêñ òèïà "zip:" (ñì. âûøå: IsMyPrefix).
932 // ìîæåò âûêèíóòü èñêëþ÷åíèå!
933 // top:
934 // <0: äîáàâèòü â íà÷àëî ñïèñêà ïîèñêà.
935 // =0: íå ìåíÿòü.
936 // >0: äîáàâèòü â êîíåö ñïèñêà ïîèñêà.
937 // permanent:
938 // <0: ñîçäàòü "âðåìåííûé" òîì.
939 // =0: íå ìåíÿòü ôëàæîê ïîñòîÿíñòâà.
940 // >0: ñîçäàòü "ïîñòîÿííûé" òîì.
941 // åñëè ds <> nil, òî ñîçäà¸ò ñáîðíèê èç ïîòîêà. åñëè ñáîðíèê ñ èìåíåì
942 // dataFileName óæå çàðåãèñòðèðîâàí, òî ïàäàåò íàôèã.
943 // âîçâðàùàåò èíäåêñ â volumes.
944 // óìååò äåëàòü ðåêóðñèþ.
945 var
953 begin
956 begin
957 // ðåêóðñèâíîå îòêðûòèå.
958 // ðàçîáü¸ì dataFileName íà èìÿ ñáîðíèêà è îñòàòîê.
959 // pfx áóäåò èìåíåì ñáîðíèêà, dataFileName -- îñòàòêîì.
961 // ñíà÷àëà îòêðîåì ïåðâûé ñïèñîê...
963 // ...òåïåðü ïðîäîëæèì ñ îñòàòêîì.
964 // óçíàåì, êàêîå ôàéëî îòêðûâàòü.
965 // âûêîâûðÿåì ïåðâûé "::" ïðåôèêñ (ýòî áóäåò èìÿ ôàéëà).
968 // dataFileName õðàíèò îñòàòîê.
969 // èçâëå÷¸ì èìÿ ôàéëà:
971 // îòêðîåì ýòîò ôàéë
973 try
976 except
978 // óäàëèì íåèñïîëüçóåìûé âðåìåííûé òîì.
979 if (gcdisabled = 0) and not vi.fPermanent and (vi.fOpenedFilesCount < 1) then volumes[result] := nil;
982 // óðà. îòêðûëè ôàéë. êèäàåì â âîçäóõ ÷åï÷èêè, ïðîäîëæàåì ðàçâëå÷åíèå.
984 try
987 except
991 exit;
994 // îáûêíîâåííîå íåðåêóðñèâíîå îòêðûòèå.
999 begin
1006 exit;
1016 try
1018 begin
1023 try
1026 except
1032 except
1038 try
1040 begin
1043 end
1045 except
1061 function SFSAddSubDataFile (const virtualName: TSFSString; ds: TStream; top: Boolean=false): Boolean;
1062 var
1064 begin
1066 try
1070 except
1076 var
1078 begin
1079 try
1083 except
1089 var
1091 begin
1092 try
1096 except
1104 var
1107 begin
1110 begin
1121 begin
1126 end
1132 var
1140 // ïðîâåðèì, åñòü ëè ôàëî fn ãäå-òî íà äèñêàõ.
1141 var
1144 begin
1151 begin
1157 try
1159 exit;
1160 except
1165 begin
1172 begin
1173 // ïðåôèêñîâàíûé ôàéë
1175 begin
1183 try
1186 except
1188 if (gcdisabled = 0) and not vi.fPermanent and (vi.fOpenedFilesCount < 1) then volumes[f] := nil;
1191 exit;
1193 //Inc(vi.fOpenedFilesCount);
1195 exit;
1198 // íåïðåôèêñîâàíûé ôàéë
1200 begin
1204 // èùåì ïî âñåì ïåðìàíåíòíûì ïðåôèêñàì
1207 begin
1210 begin
1212 begin
1215 begin
1216 try
1219 //Inc(vi.fOpenedFilesCount);
1220 except
1234 begin
1235 try
1237 except
1243 var
1246 begin
1250 try
1252 except
1253 exit;
1257 try
1260 except
1261 if (gcdisabled = 0) and not vi.fPermanent and (vi.fOpenedFilesCount < 1) then volumes[f] := nil;
1266 initialization
1269 //finalization
1270 //volumes.Free(); // it fails for some reason... Runtime 217 (^C hit). wtf?!
1271 //factories.Free(); // not need to be done actually...