diff --git a/base/applications/mscutils/servman/lang/pl-PL.rc b/base/applications/mscutils/servman/lang/pl-PL.rc index ea785ed3433..df0759c7e9f 100644 --- a/base/applications/mscutils/servman/lang/pl-PL.rc +++ b/base/applications/mscutils/servman/lang/pl-PL.rc @@ -4,6 +4,7 @@ * https://sourceforge.net/projects/reactospl * * updated by Caemyr - Olaf Siejka (Jan, 2008) + * updated by Saibamen - Adam Stachowicz (Mar, 2011) */ LANGUAGE LANG_POLISH, SUBLANG_DEFAULT @@ -46,7 +47,7 @@ BEGIN POPUP "Pomoc" BEGIN MENUITEM "Pomoc", ID_HELP - MENUITEM "Servman - informacje", ID_ABOUT + MENUITEM "O programie", ID_ABOUT END END @@ -72,11 +73,11 @@ BEGIN END IDD_ABOUTBOX DIALOGEX 22,16,190,182 -CAPTION "Service Manager - informacje" +CAPTION "Mened¿er Us³ug - informacje" FONT 8, "MS Shell Dlg",0,0 STYLE DS_SHELLFONT | WS_BORDER | WS_DLGFRAME | WS_SYSMENU | DS_MODALFRAME BEGIN - LTEXT "Service Manager v0.5.1\nCopyright (C) 2005-2006\nby Ged Murphy (gedmurphy@gmail.com)", IDC_STATIC, 48, 7, 135, 26 + LTEXT "Mened¿er Us³ug v0.5.1\nCopyright (C) 2005-2006\nby Ged Murphy (gedmurphy@gmail.com)", IDC_STATIC, 48, 7, 135, 26 PUSHBUTTON "Zamknij", IDOK, 75, 162, 44, 15 ICON IDI_SM_ICON, IDC_STATIC, 10, 10, 7, 30 EDITTEXT IDC_LICENSE_EDIT, 8, 44, 174, 107, WS_VISIBLE | WS_VSCROLL | WS_TABSTOP | ES_READONLY | ES_MULTILINE @@ -198,8 +199,8 @@ END STRINGTABLE DISCARDABLE BEGIN IDS_NUM_SERVICES "Numer us³ugi: %d" - IDS_STOP_DEPENDS "When %s stops, these other services will also stop" - IDS_NO_DEPENDS "" + IDS_STOP_DEPENDS "Kiedy %s siê zatrzyma, inne us³ugi równie¿ siê zatrzymaj¹" + IDS_NO_DEPENDS "" IDS_LICENSE "Niniejszy program jest wolnym oprogramowaniem; mo¿esz go rozprowadzaæ dalej i/lub modyfikowaæ na warunkach Powszechnej Licencji Publicznej GNU, wydanej przez Fundacjê Wolnego Oprogramowania - wed³ug wersji 2 tej Licencji lub (wed³ug Twojego wyboru) którejœ z póŸniejszych wersji.\r\n\r\nNiniejszy program rozpowszechniany jest z nadziej¹, i¿ bêdzie on u¿yteczny - jednak BEZ JAKIEJKOLWIEK GWARANCJI, nawet domyœlnej gwarancji PRZYDATNOŒCI HANDLOWEJ albo PRZYDATNOŒCI DO OKREŒLONYCH ZASTOSOWAÑ. W celu uzyskania bli¿szych informacji siêgnij do Powszechnej Licencji Publicznej GNU.\r\n\r\nZ pewnoœci¹ wraz z niniejszym programem otrzyma³eœ te¿ egzemplarz Powszechnej Licencji Publicznej GNU (GNU General Public License); jeœli nie - napisz do Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA." END diff --git a/base/applications/network/ping/ping.c b/base/applications/network/ping/ping.c index 6f7935e9159..c0bd93201a1 100644 --- a/base/applications/network/ping/ping.c +++ b/base/applications/network/ping/ping.c @@ -59,7 +59,6 @@ typedef struct _ICMP_ECHO_PACKET #pragma pack(1) -BOOL InvalidOption; BOOL NeverStop; BOOL ResolveAddresses; UINT PingCount; @@ -213,84 +212,71 @@ static VOID Reset(VOID) } } -/* Return ULONG in a string */ -static ULONG GetULONG(LPWSTR String) -{ - UINT i, Length; - ULONG Value; - LPWSTR StopString; - i = 0; - Length = (UINT)wcslen(String); - while ((i < Length) && ((String[i] < L'0') || (String[i] > L'9'))) i++; - if ((i >= Length) || ((String[i] < L'0') || (String[i] > L'9'))) - { - InvalidOption = TRUE; - return 0; - } - Value = wcstoul(&String[i], &StopString, 10); - - return Value; -} - -/* Return ULONG in a string. Try next paramter if not successful */ -static ULONG GetULONG2(LPWSTR String1, LPWSTR String2, PINT i) -{ - ULONG Value; - - Value = GetULONG(String1); - if (InvalidOption) - { - InvalidOption = FALSE; - if (String2[0] != L'-') - { - Value = GetULONG(String2); - if (!InvalidOption) - *i += 1; - } - } - - return Value; -} - /* Parse command line parameters */ static BOOL ParseCmdline(int argc, LPWSTR argv[]) { INT i; - BOOL ShowUsage; - BOOL FoundTarget; + BOOL FoundTarget = FALSE, InvalidOption = FALSE; + if (argc < 2) - ShowUsage = TRUE; - else - ShowUsage = FALSE; - FoundTarget = FALSE; - InvalidOption = FALSE; + { + Usage(); + return FALSE; + } for (i = 1; i < argc; i++) { - if (argv[i][0] == L'-') + if (argv[i][0] == L'-' || argv[i][0] == L'/') { switch (argv[i][1]) { case L't': NeverStop = TRUE; break; case L'a': ResolveAddresses = TRUE; break; - case L'n': PingCount = GetULONG2(&argv[i][2], argv[i + 1], &i); break; + case L'n': + if (i + 1 < argc) + PingCount = wcstoul(argv[++i], NULL, 0); + else + InvalidOption = TRUE; + break; case L'l': - DataSize = GetULONG2(&argv[i][2], argv[i + 1], &i); - if (DataSize > ICMP_MAXSIZE - sizeof(ICMP_ECHO_PACKET) - sizeof(IPv4_HEADER)) + if (i + 1 < argc) { - FormatOutput(IDS_BAD_VALUE_OPTION_L, ICMP_MAXSIZE - \ - (int)sizeof(ICMP_ECHO_PACKET) - \ - (int)sizeof(IPv4_HEADER)); - return FALSE; - } + DataSize = wcstoul(argv[++i], NULL, 0); + + if (DataSize > ICMP_MAXSIZE - sizeof(ICMP_ECHO_PACKET) - sizeof(IPv4_HEADER)) + { + FormatOutput(IDS_BAD_VALUE_OPTION_L, ICMP_MAXSIZE - \ + (int)sizeof(ICMP_ECHO_PACKET) - \ + (int)sizeof(IPv4_HEADER)); + return FALSE; + } + } else + InvalidOption = TRUE; break; case L'f': DontFragment = TRUE; break; - case L'i': TTLValue = GetULONG2(&argv[i][2], argv[i + 1], &i); break; - case L'v': TOSValue = GetULONG2(&argv[i][2], argv[i + 1], &i); break; - case L'w': Timeout = GetULONG2(&argv[i][2], argv[i + 1], &i); break; + case L'i': + if (i + 1 < argc) + TTLValue = wcstoul(argv[++i], NULL, 0); + else + InvalidOption = TRUE; + break; + case L'v': + if (i + 1 < argc) + TOSValue = wcstoul(argv[++i], NULL, 0); + else + InvalidOption = TRUE; + break; + case L'w': + if (i + 1 < argc) + Timeout = wcstoul(argv[++i], NULL, 0); + else + InvalidOption = TRUE; + break; + case '?': + Usage(); + return FALSE; default: FormatOutput(IDS_BAD_OPTION, argv[i]); - Usage(); return FALSE; } if (InvalidOption) @@ -314,17 +300,12 @@ static BOOL ParseCmdline(int argc, LPWSTR argv[]) } } - if ((!ShowUsage) && (!FoundTarget)) + if (!FoundTarget) { FormatOutput(IDS_DEST_MUST_BE_SPECIFIED); return FALSE; } - if (ShowUsage) - { - Usage(); - return FALSE; - } return TRUE; } diff --git a/base/applications/rapps/rapps/comctl32ocx.txt b/base/applications/rapps/rapps/comctl32ocx.txt index b0aac593814..47494f3fb43 100644 --- a/base/applications/rapps/rapps/comctl32ocx.txt +++ b/base/applications/rapps/rapps/comctl32ocx.txt @@ -4,7 +4,7 @@ Name = Microsoft Visual Basic 6.0 Common Controls Version = 6.0 Licence = Unknown -Description = File needed by some applications. +Description = File needed by some applications. Contains: comctl32.ocx, mscomctl.ocx, advpack.dll. Size = 914kB Category = 14 URLSite = http://www.microsoft.com/downloads/details.aspx?FamilyID=25437D98-51D0-41C1-BB14-64662F5F62FE&displaylang=en diff --git a/base/applications/rapps/rapps/doublecommander.txt b/base/applications/rapps/rapps/doublecommander.txt new file mode 100644 index 00000000000..12169d2fd90 --- /dev/null +++ b/base/applications/rapps/rapps/doublecommander.txt @@ -0,0 +1,21 @@ +; UTF-8 + +[Section] +Name = Double Commander +Version = 0.4.5.2 beta +Licence = GPL +Description = Double Commander is an open source file manager with two panels side by side. You need 7-Zip or a similar Utility to extract it. +Size = 6.71MB +Category = 12 +URLSite = http://doublecmd.sourceforge.net/ +URLDownload = http://ignum.dl.sourceforge.net/project/doublecmd/DC%20for%20Windows%2032%20bit/Double%20Commander%200.4.5.2%20beta/doublecmd-0.4.5.2.i386-win32.zip +CDPath = none + +[Section.0415] +Description = Double Commander to menedżer plików, o otwartym źródle, z klasycznym ukÅ‚adem dwóch paneli obok siebie. Do rozpakowania archiwum potrzebny jest 7-zip lub podobny program. + +[Section.0419] +Description = Double Commander - Ñто открытый двухпанельный файловый менеджер. Вам нужен 7-Zip или Ð¿Ð¾Ð´Ð¾Ð±Ð½Ð°Ñ ÑƒÑ‚Ð¸Ð»Ð¸Ñ‚Ð° Ð´Ð»Ñ ÐµÐ³Ð¾ раÑпаковки. + +[Section.0422] +Description = Double Commander - це відкритий двопанельний файловий менеджер. Вам потрібен 7-Zip або подібна утиліта щоб розпакувати його. \ No newline at end of file diff --git a/base/applications/rapps/rapps/firefox36.txt b/base/applications/rapps/rapps/firefox36.txt index 4f5d3b8c96b..207565f77b1 100644 --- a/base/applications/rapps/rapps/firefox36.txt +++ b/base/applications/rapps/rapps/firefox36.txt @@ -2,53 +2,53 @@ [Section] Name = Mozilla Firefox 3.6 -Version = 3.6.15 +Version = 3.6.16 Licence = MPL/GPL/LGPL Description = The most popular and one of the best free Web Browsers out there. Size = 8.2M Category = 5 URLSite = http://www.mozilla.com/en-US/ -URLDownload = http://mozilla.cdn.leaseweb.com/firefox/releases/3.6.15/win32/en-US/Firefox%20Setup%203.6.15.exe +URLDownload = http://mozilla.cdn.leaseweb.com/firefox/releases/3.6.16/win32/en-US/Firefox%20Setup%203.6.16.exe CDPath = none [Section.0407] Description = Der populärste und einer der besten freien Webbrowser. Size = 8.1M URLSite = http://www.mozilla-europe.org/de/ -URLDownload = http://mozilla.cdn.leaseweb.com/firefox/releases/3.6.15/win32/de/Firefox%20Setup%203.6.15.exe +URLDownload = http://mozilla.cdn.leaseweb.com/firefox/releases/3.6.16/win32/de/Firefox%20Setup%203.6.16.exe [Section.040a] Description = El más popular y uno de los mejores navegadores web gratuitos que hay. Size = 8.1M URLSite = http://www.mozilla-europe.org/es/ -URLDownload = http://mozilla.cdn.leaseweb.com/firefox/releases/3.6.15/win32/es-ES/Firefox%20Setup%203.6.15.exe +URLDownload = http://mozilla.cdn.leaseweb.com/firefox/releases/3.6.16/win32/es-ES/Firefox%20Setup%203.6.16.exe [Section.040c] Description = Le navigateur web gratuit le plus populaire et l'un des meilleurs. Size = 8.1M URLSite = http://www.mozilla-europe.org/fr/ -URLDownload = http://mozilla.cdn.leaseweb.com/firefox/releases/3.6.15/win32/fr/Firefox%20Setup%203.6.15.exe +URLDownload = http://mozilla.cdn.leaseweb.com/firefox/releases/3.6.16/win32/fr/Firefox%20Setup%203.6.16.exe [Section.0414] Description = Mest populære og best ogsÃ¥ gratis nettleserene der ute. Size = 8.1M URLSite = http://www.mozilla-europe.org/no/ -URLDownload = http://mozilla.cdn.leaseweb.com/firefox/releases/3.6.15/win32/nb-NO/Firefox%20Setup%203.6.15.exe +URLDownload = http://mozilla.cdn.leaseweb.com/firefox/releases/3.6.16/win32/nb-NO/Firefox%20Setup%203.6.16.exe [Section.0415] Description = Najpopularniejsza i jedna z najlepszych darmowych przeglÄ…darek internetowych. Size = 8.9M URLSite = http://www.mozilla-europe.org/pl/ -URLDownload = http://mozilla.cdn.leaseweb.com/firefox/releases/3.6.15/win32/pl/Firefox%20Setup%203.6.15.exe +URLDownload = http://mozilla.cdn.leaseweb.com/firefox/releases/3.6.16/win32/pl/Firefox%20Setup%203.6.16.exe [Section.0419] Description = Один из Ñамых популÑрных и лучших беÑплатных браузеров. Size = 8.5M URLSite = http://www.mozilla-europe.org/ru/ -URLDownload = http://mozilla.cdn.leaseweb.com/firefox/releases/3.6.15/win32/ru/Firefox%20Setup%203.6.15.exe +URLDownload = http://mozilla.cdn.leaseweb.com/firefox/releases/3.6.16/win32/ru/Firefox%20Setup%203.6.16.exe [Section.0422] Description = ÐайпопулÑрніший та один з кращих безплатних веб-браузерів. Size = 8.5M URLSite = http://www.mozilla-europe.org/uk/ -URLDownload = http://mozilla.cdn.leaseweb.com/firefox/releases/3.6.15/win32/uk/Firefox%20Setup%203.6.15.exe +URLDownload = http://mozilla.cdn.leaseweb.com/firefox/releases/3.6.16/win32/uk/Firefox%20Setup%203.6.16.exe diff --git a/base/applications/rapps/rapps/go-oo.txt b/base/applications/rapps/rapps/go-oo.txt deleted file mode 100644 index 28e9fa68f1a..00000000000 --- a/base/applications/rapps/rapps/go-oo.txt +++ /dev/null @@ -1,27 +0,0 @@ -; UTF-8 - -[Section] -Name = Go-OO -Version = 3.2.1-11 -Licence = LGPL -Description = Open Source Office Suite, based on Open Office, but way better. -Size = 181.0MB -Category = 6 -URLSite = http://www.go-oo.org/ -URLDownload = http://go-oo.mirrorbrain.org/stable/win32/3.2.1/GoOo-3.2.1-11.exe -CDPath = none - -[Section.0407] -Description = Open Source Office Suite, basierend auf Open Office, aber viel besser. - -[Section.040a] -Description = La suite de ofimática de código abierto. - -[Section.040c] -Description = Suite bureautique open source basée sur Open Office, mais bien meilleure. - -[Section.0415] -Description = Otwarty pakiet biurowy, bazujÄ…cy na Open Office, ale znacznie lepszy. - -[Section.0422] -Description = Відкритий офіÑний пакет. diff --git a/base/applications/rapps/rapps/libreoffice.txt b/base/applications/rapps/rapps/libreoffice.txt index 93805ef8f7d..d609e3f80b4 100644 --- a/base/applications/rapps/rapps/libreoffice.txt +++ b/base/applications/rapps/rapps/libreoffice.txt @@ -2,13 +2,13 @@ [Section] Name = LibreOffice -Version = 3.3.1 +Version = 3.3.2 Licence = LGPL Description = Former called OpenOffice. Open Source Office Suite. -Size = 213.4MB +Size = 214.0MB Category = 6 URLSite = http://www.documentfoundation.org/ -URLDownload = http://download.documentfoundation.org/libreoffice/stable/3.3.1/win/x86/LibO_3.3.1_Win_x86_install_multi.exe +URLDownload = http://download.documentfoundation.org/libreoffice/stable/3.3.2/win/x86/LibO_3.3.2_Win_x86_install_multi.exe CDPath = none [Section.0407] diff --git a/base/applications/rapps/rapps/mfc40.txt b/base/applications/rapps/rapps/mfc40.txt index 58e1f4ebe02..b732baa385e 100644 --- a/base/applications/rapps/rapps/mfc40.txt +++ b/base/applications/rapps/rapps/mfc40.txt @@ -4,7 +4,7 @@ Name = OLE Viewer and Microsoft Foundation Classes version 4 Version = 4.0 Licence = Unknown -Description = MFC 4 is needed by some applications. +Description = MFC 4 is needed by some applications. Contains: mfc40.dll, msvcrt40.dll. Size = 865kB Category = 14 URLSite = http://support.microsoft.com/kb/122244/ diff --git a/base/applications/rapps/rapps/mirandaim.txt b/base/applications/rapps/rapps/mirandaim.txt index 68ff3854ab0..9e1198eb888 100644 --- a/base/applications/rapps/rapps/mirandaim.txt +++ b/base/applications/rapps/rapps/mirandaim.txt @@ -2,13 +2,13 @@ [Section] Name = Miranda IM -Version = 0.9.17 +Version = 0.9.18 Licence = GPL Description = Open source multiprotocol instant messaging application - May not work completely. Size = 3.0MB Category = 5 URLSite = http://www.miranda-im.org/ -URLDownload = http://miranda.googlecode.com/files/miranda-im-v0.9.17-unicode.exe +URLDownload = http://miranda.googlecode.com/files/miranda-im-v0.9.18-unicode.exe CDPath = none [Section.0407] diff --git a/base/applications/rapps/rapps/msxml3.txt b/base/applications/rapps/rapps/msxml3.txt index 788488af34c..d023aa69db9 100644 --- a/base/applications/rapps/rapps/msxml3.txt +++ b/base/applications/rapps/rapps/msxml3.txt @@ -4,11 +4,11 @@ Name = Microsoft XML 3 Version = 3.0 Licence = Unknown -Description = MSXML3 is needed for some MSI Installers. +Description = MSXML3 is needed for some MSI Installers. Contains: msxml3.dll, msxml3a.dll, msxml3r.dll. Size = 1.0MB Category = 14 URLSite = http://www.microsoft.com/downloads/details.aspx?FamilyID=28494391-052B-42FF-9674-F752BDCA9582&displaylang=en -URLDownload = http://download.microsoft.com/download/8/8/8/888f34b7-4f54-4f06-8dac-fa29b19f33dd/msxml3.msi +URLDownload = ftp://ftp.uni-rostock.de/pub/tools/microsoft/XML/US/msxml3.msi CDPath = none [Section.0407] diff --git a/base/applications/rapps/rapps/scite.txt b/base/applications/rapps/rapps/scite.txt index a323c6d24a1..b9e287e025a 100644 --- a/base/applications/rapps/rapps/scite.txt +++ b/base/applications/rapps/rapps/scite.txt @@ -2,13 +2,13 @@ [Section] Name = SciTE -Version = 2.24 +Version = 2.25 Licence = Freeware Description = SciTE is a SCIntilla based Text Editor. Originally built to demonstrate Scintilla, it has grown to be a generally useful editor with facilities for building and running programs. Size = 0.6M Category = 7 URLSite = http://www.scintilla.org/ -URLDownload = http://kent.dl.sourceforge.net/project/scintilla/SciTE/2.24/Sc224.exe +URLDownload = http://kent.dl.sourceforge.net/project/scintilla/SciTE/2.25/Sc225.exe CDPath = none [Section.0407] diff --git a/base/applications/rapps/rapps/seamonkey.txt b/base/applications/rapps/rapps/seamonkey.txt index 2564895cac8..48579604d39 100644 --- a/base/applications/rapps/rapps/seamonkey.txt +++ b/base/applications/rapps/rapps/seamonkey.txt @@ -2,36 +2,36 @@ [Section] Name = Mozilla SeaMonkey -Version = 2.0.12 +Version = 2.0.13 Licence = MPL/GPL/LGPL Description = Mozilla Suite is alive. This is the one and only Browser, Mail, Chat, and Composer bundle you will ever need. Size = 10.2MB Category = 5 URLSite = http://www.seamonkey-project.org/ -URLDownload = http://releases.mozilla.org/pub/mozilla.org/seamonkey/releases/2.0.12/win32/en-US/SeaMonkey%20Setup%202.0.12.exe +URLDownload = http://releases.mozilla.org/pub/mozilla.org/seamonkey/releases/2.0.13/win32/en-US/SeaMonkey%20Setup%202.0.13.exe CDPath = none [Section.0407] Description = Mozilla Suite lebt. Dies ist das einzige Browser-, Mail-, Chat- and Composerwerkzeug-Bundle welches Sie benötigen. Size = 10.1MB -URLDownload = http://releases.mozilla.org/pub/mozilla.org/seamonkey/releases/2.0.12/win32/de/SeaMonkey%20Setup%202.0.12.exe +URLDownload = http://releases.mozilla.org/pub/mozilla.org/seamonkey/releases/2.0.13/win32/de/SeaMonkey%20Setup%202.0.13.exe [Section.040a] Description = La suite de Mozilla está viva. Es el primero y único navegador web, gestor de correo, lector de noticias, Chat y editor HTML que necesitarás. Size = 10.1MB -URLDownload = http://releases.mozilla.org/pub/mozilla.org/seamonkey/releases/2.0.12/win32/es-ES/SeaMonkey%20Setup%202.0.12.exe +URLDownload = http://releases.mozilla.org/pub/mozilla.org/seamonkey/releases/2.0.13/win32/es-ES/SeaMonkey%20Setup%202.0.13.exe [Section.040c] Description = La suite Mozilla est en vie. Ceci est le seul et l'unique package navigateur, client mail, client chat et composer dont vous aurez besoin. Size = 10.1MB -URLDownload = http://releases.mozilla.org/pub/mozilla.org/seamonkey/releases/2.0.12/win32/fr/SeaMonkey%20Setup%202.0.12.exe +URLDownload = http://releases.mozilla.org/pub/mozilla.org/seamonkey/releases/2.0.13/win32/fr/SeaMonkey%20Setup%202.0.13.exe [Section.0415] Description = Pakiet Mozilla żyje. W zestawie: przeglÄ…darka, klient poczty, IRC oraz Edytor HTML - wszystko, czego potrzebujesz. Size = 11.0MB -URLDownload = http://releases.mozilla.org/pub/mozilla.org/seamonkey/releases/2.0.12/win32/pl/SeaMonkey%20Setup%202.0.12.exe +URLDownload = http://releases.mozilla.org/pub/mozilla.org/seamonkey/releases/2.0.13/win32/pl/SeaMonkey%20Setup%202.0.13.exe [Section.0419] Description = Продолжение Mozilla Suite. Включает браузер, почтовый клиент, IRC-клиент и HTML-редактор. Size = 10.5MB -URLDownload = http://releases.mozilla.org/pub/mozilla.org/seamonkey/releases/2.0.12/win32/ru/SeaMonkey%20Setup%202.0.12.exe +URLDownload = http://releases.mozilla.org/pub/mozilla.org/seamonkey/releases/2.0.13/win32/ru/SeaMonkey%20Setup%202.0.13.exe diff --git a/base/applications/rapps/rapps/tahoma.txt b/base/applications/rapps/rapps/tahoma.txt index 68181fd4e0e..41addaf0e6a 100644 --- a/base/applications/rapps/rapps/tahoma.txt +++ b/base/applications/rapps/rapps/tahoma.txt @@ -4,7 +4,7 @@ Name = Microsoft Tahoma Font Version = 1.0 Licence = Unknown -Description = Tahoma Font pack needed by some apps (Steam). +Description = Tahoma Font pack needed by some apps (Steam). Contains: Tahoma.tff, Tahomabd.ttf. Size = 305kB Category = 14 URLSite = http://support.microsoft.com/ diff --git a/base/applications/rapps/rapps/vb5run.txt b/base/applications/rapps/rapps/vb5run.txt index 12fb70ef3e9..a2847618589 100644 --- a/base/applications/rapps/rapps/vb5run.txt +++ b/base/applications/rapps/rapps/vb5run.txt @@ -4,7 +4,7 @@ Name = Visual Basic 5 Runtime Version = 5.0 Licence = Unknown -Description = Visual Basic 5 Runtime. +Description = Visual Basic 5 Runtime. Contains: advpack.dll, asycfilt.dll, comcat.dll, msvbvm50.dll, oleaut32.dll, olepro32.dll. Size = 970kB Category = 14 URLSite = http://support.microsoft.com/kb/180071/ diff --git a/base/applications/rapps/rapps/vb6run.txt b/base/applications/rapps/rapps/vb6run.txt index 542b977c95d..a7f34a12ed6 100644 --- a/base/applications/rapps/rapps/vb6run.txt +++ b/base/applications/rapps/rapps/vb6run.txt @@ -4,7 +4,7 @@ Name = Visual Basic 6 Runtime Version = 6.0 Licence = Unknown -Description = Visual Basic 6 Runtime. +Description = Visual Basic 6 Runtime. Contains: advpack.dll, asycfilt.dll, comcat.dll, msvbvm60.dll, oleaut32.dll, olepro32.dll. Size = 1.0MB Category = 14 URLSite = http://support.microsoft.com/kb/192461/ diff --git a/base/applications/rapps/rapps/vc2005run.txt b/base/applications/rapps/rapps/vc2005run.txt deleted file mode 100644 index 50b68787d2c..00000000000 --- a/base/applications/rapps/rapps/vc2005run.txt +++ /dev/null @@ -1,32 +0,0 @@ -; UTF-8 - -[Section] -Name = Microsoft Visual C++ 2005 Redistributable Package -Version = 7.0 -Licence = Unknown -Description = Visual Studio 2005 Runtime. -Size = 2.6MB -Category = 14 -URLSite = http://www.microsoft.com/Downloads/details.aspx?displaylang=en&FamilyID=32bc1bee-a3f9-4c13-9c99-220b62a191ee -URLDownload = http://download.microsoft.com/download/6/B/B/6BB661D6-A8AE-4819-B79F-236472F6070C/vcredist_x86.exe -CDPath = none - -[Section.0407] -Licence = Unbekannt -Description = Visual Studio 2005 Laufzeitsystem. - -[Section.040a] -Licence = Desconocida -Description = Librerias Visual Studio 2005. - -[Section.040c] -Licence = Inconnue -Description = Bibliothèque Visual Studio 2005. - -[Section.0415] -Licence = Nieznana -Description = Biblioteki uruchomieniowe Visual Studio 2005. - -[Section.0422] -Licence = Ðевідома -Description = Бібліотеки Visual Studio 2005. diff --git a/base/applications/rapps/rapps/vc2005sp1run.txt b/base/applications/rapps/rapps/vc2005sp1run.txt index 40a8a5dee88..b8966eaebc1 100644 --- a/base/applications/rapps/rapps/vc2005sp1run.txt +++ b/base/applications/rapps/rapps/vc2005sp1run.txt @@ -4,7 +4,7 @@ Name = Microsoft Visual C++ 2005 SP1 Redistributable Package Version = 7.1 Licence = Unknown -Description = Visual Studio 2005 Runtime SP1. +Description = Visual Studio 2005 Runtime SP1. Contains: atl80.dll, mfc80.dll, mfcm80.dll, mfcm80u.dll, msdia80.dll, msvcm80.dll, msvcp80.dll, msvcr80.dll, vcomp.dll. Size = 2.6MB Category = 14 URLSite = http://www.microsoft.com/downloads/details.aspx?FamilyID=200b2fd9-ae1a-4a14-984d-389c36f85647&displaylang=en diff --git a/base/applications/rapps/rapps/vc2008run.txt b/base/applications/rapps/rapps/vc2008run.txt deleted file mode 100644 index b6bf3443feb..00000000000 --- a/base/applications/rapps/rapps/vc2008run.txt +++ /dev/null @@ -1,32 +0,0 @@ -; UTF-8 - -[Section] -Name = Microsoft Visual C++ 2008 Redistributable Package -Version = 8.0 -Licence = Unknown -Description = Visual Studio 2008 Runtime. -Size = 4.3MB -Category = 14 -URLSite = http://www.microsoft.com/DOWNLOADS/details.aspx?FamilyID=9b2da534-3e03-4391-8a4d-074b9f2bc1bf&displaylang=en -URLDownload = http://download.microsoft.com/download/9/7/7/977B481A-7BA6-4E30-AC40-ED51EB2028F2/vcredist_x86.exe -CDPath = none - -[Section.0407] -Licence = Unbekannt -Description = Visual Studio 2008 Laufzeitsystem. - -[Section.040a] -Licence = Desconocida -Description = Librerias Visual Studio 2008. - -[Section.040c] -Licence = Inconnue -Description = Bibliothèque Visual Studio 2008. - -[Section.0415] -Licence = Nieznana -Description = Biblioteki uruchomieniowe Visual Studio 2008. - -[Section.0422] -Licence = Ðевідома -Description = Бібліотеки Visual Studio 2008. diff --git a/base/applications/rapps/rapps/vc2008sp1run.txt b/base/applications/rapps/rapps/vc2008sp1run.txt index 0f05a041bc6..2743f24c607 100644 --- a/base/applications/rapps/rapps/vc2008sp1run.txt +++ b/base/applications/rapps/rapps/vc2008sp1run.txt @@ -4,7 +4,7 @@ Name = Microsoft Visual C++ 2008 SP1 Redistributable Package Version = 8.0 Licence = Unknown -Description = Visual Studio 2008 SP1 Runtime. +Description = Visual Studio 2008 SP1 Runtime. Contains: atl90.dll, mfc90.dll, mfc90u.dll, mfcm90.dll, mfcm90u.dll, msdia90.dll, msvcm90.dll, msvcp90.dll, msvcr90.dll, vcomp90.dll. Size = 4.0MB Category = 14 URLSite = http://www.microsoft.com/downloads/details.aspx?familyid=A5C84275-3B97-4AB7-A40D-3802B2AF5FC2&displaylang=en diff --git a/base/applications/rapps/rapps/vc6run.txt b/base/applications/rapps/rapps/vc6run.txt index 9ed5a088034..0f45b98a420 100644 --- a/base/applications/rapps/rapps/vc6run.txt +++ b/base/applications/rapps/rapps/vc6run.txt @@ -4,7 +4,7 @@ Name = Microsoft Visual C++ 6 Redistributable Package Version = 6.0 Licence = Unknown -Description = Visual Studio 6 Runtime. +Description = Visual Studio 6 Runtime. Contains: advpack.dll, asycfilt.dll, atla.dll, atlu.dll, comcat.dll, mfc42.dll, mfc42u.dll, msvcirt.dll, msvcp60.dll, msvcrt.dll, oleaut32.dll, olepro32.dll. Size = 1.7MB Category = 14 URLSite = http://support.microsoft.com/kb/259403/ diff --git a/base/applications/rapps/rapps/vlc.txt b/base/applications/rapps/rapps/vlc.txt index ae94d897561..0e35475c489 100644 --- a/base/applications/rapps/rapps/vlc.txt +++ b/base/applications/rapps/rapps/vlc.txt @@ -2,13 +2,13 @@ [Section] Name = VLC media player -Version = 1.1.7 +Version = 1.1.8 Licence = GPL Description = A media player. -Size = 19.4MB +Size = 19.6MB Category = 1 URLSite = http://www.videolan.org/vlc/ -URLDownload = http://kent.dl.sourceforge.net/project/vlc/1.1.7/win32/vlc-1.1.7-win32.exe +URLDownload = http://kent.dl.sourceforge.net/project/vlc/1.1.8/win32/vlc-1.1.8-win32.exe CDPath = none [Section.0407] diff --git a/base/applications/sndvol32/mixer.c b/base/applications/sndvol32/mixer.c index b085fe95fb3..f01496c7ed3 100644 --- a/base/applications/sndvol32/mixer.c +++ b/base/applications/sndvol32/mixer.c @@ -189,7 +189,7 @@ SndMixerQueryConnections(PSND_MIXER Mixer, MIXER_GETLINEINFOF_SOURCE); if (Result == MMSYSERR_NOERROR) { - LPMIXERCONTROL Controls; + LPMIXERCONTROL Controls = NULL; PSND_MIXER_CONNECTION Con; DPRINT("++ Source: %ws\n", LineInfo.szName); diff --git a/base/shell/cmd/dir.c b/base/shell/cmd/dir.c index ce1e5657771..e648f0cbde4 100644 --- a/base/shell/cmd/dir.c +++ b/base/shell/cmd/dir.c @@ -680,10 +680,10 @@ FormatTime(TCHAR *lpTime, LPSYSTEMTIME dt) { case 0: /* 12 hour format */ default: - return _stprintf(lpTime,_T("%02d%c%02u%c"), + return _stprintf(lpTime,_T("%02d%c%02u %cM"), (dt->wHour == 0 ? 12 : (dt->wHour <= 12 ? dt->wHour : dt->wHour - 12)), cTimeSeparator, - dt->wMinute, (dt->wHour <= 11 ? _T('a') : _T('p'))); + dt->wMinute, (dt->wHour <= 11 ? _T('A') : _T('P'))); break; case 1: /* 24 hour format */ diff --git a/base/shell/cmd/lang/ru-RU.rc b/base/shell/cmd/lang/ru-RU.rc index 97b3d4aef5b..c09389263fb 100644 --- a/base/shell/cmd/lang/ru-RU.rc +++ b/base/shell/cmd/lang/ru-RU.rc @@ -19,291 +19,291 @@ assoc .ext (print specific association)\n\ assoc .ext= (remove specific association)\n\ assoc .ext=FileType (add new association)\n" -STRING_ATTRIB_HELP, "Âûâîä è èçìåíåíèå àòðèáóòîâ ôàéëîâ.\n\n\ -ATTRIB [+R | -R] [+A | -A] [+S | -S] [+H | -H] ôàéë ...\n\ +STRING_ATTRIB_HELP, "Вывод и изменение атрибутов файлов.\n\n\ +ATTRIB [+R | -R] [+A | -A] [+S | -S] [+H | -H] файл ...\n\ [/S [/D]]\n\n\ - + Óñòàíîâêà àòðèáóòà.\n\ - - Ñíÿòèå àòðèáóòà.\n\ - R Àòðèáóò ""Òîëüêî ÷òåíèå"".\n\ - A Àòðèáóò ""Àðõèâíûé"".\n\ - S Àòðèáóò ""Ñèñòåìíûé"".\n\ - H Àòðèáóò ""Ñêðûòûé"".\n\ - /S Îáðàáîòêà ôàéëîâ ñ óêàçàííûìè èìåíàìè â òåêóùåé ïàïêå\n\ -è âî âñåõ åå ïîäïàïêàõ.\n\ - /D Îáðàáîòêà è ôàéëîâ, è ïàïîê.\n\n\ -ATTRIB áåç ïàðàìåòðîâ âûâîäèò àòðèáóòû âñåõ ôàéëîâ.\n" + + УÑтановка атрибута.\n\ + - СнÑтие атрибута.\n\ + R Ðтрибут ""Только чтение"".\n\ + A Ðтрибут ""Ðрхивный"".\n\ + S Ðтрибут ""СиÑтемный"".\n\ + H Ðтрибут ""Скрытый"".\n\ + /S Обработка файлов Ñ ÑƒÐºÐ°Ð·Ð°Ð½Ð½Ñ‹Ð¼Ð¸ именами в текущей папке\n\ +и во вÑех ее подпапках.\n\ + /D Обработка и файлов, и папок.\n\n\ +ATTRIB без параметров выводит атрибуты вÑех файлов.\n" -STRING_ALIAS_HELP, "Âûâîä, óñòàíîâêà èëè óäàëåíèå ïñåâäîíèìîâ.\n\n\ -ALIAS [ïñåâäîíèì=[êîìàíäà]]\n\n\ - ïñåâäîíèì Ãàèìåíîâàíèå ïñåâäîíèìà.\n\ - êîìàíäà Òåêñò, ïîäñòàâëÿåìûé âìåñòî ïñåâäîíèìà.\n\n\ -Âûâîä ñïèñêà âñåõ ïñåâäîíèìîâ:\n\ +STRING_ALIAS_HELP, "Вывод, уÑтановка или удаление пÑевдонимов.\n\n\ +ALIAS [пÑевдоним=[команда]]\n\n\ + пÑевдоним Ðаименование пÑевдонима.\n\ + команда ТекÑÑ‚, подÑтавлÑемый вмеÑто пÑевдонима.\n\n\ +Вывод ÑпиÑка вÑех пÑевдонимов:\n\ ALIAS\n\n\ -Óñòàíîâêà èëè èçìåíåíèå ñóùåñòâóþùåãî ïñåâäîíèìà:\n\ +УÑтановка или изменение ÑущеÑтвующего пÑевдонима:\n\ ALIAS da=dir a:\n\n\ -Óäàëåíèå ïñåâäîíèìà èç ñïèñêà:\n\ +Удаление пÑевдонима из ÑпиÑка:\n\ ALIAS da=" -STRING_BEEP_HELP, "Çâóêîâîé ñèãíàë.\n\nBEEP\n" +STRING_BEEP_HELP, "Звуковой Ñигнал.\n\nBEEP\n" -STRING_CALL_HELP, "Âûçîâ îäíîãî ïàêåòíîãî ôàéëà èç äðóãîãî.\n\n\ -CALL [äèñê:][ïóòü]èìÿ_ôàéëà [ïàðàìåòðû]\n\n\ - ïàðàìåòðû Ãàáîð ïàðàìåòðîâ êîìàíäíîé ñòðîêè, íåîáõîäèìûõ\n\ - ïàêåòíîìó ôàéëó." +STRING_CALL_HELP, "Вызов одного пакетного файла из другого.\n\n\ +CALL [диÑк:][путь]имÑ_файла [параметры]\n\n\ + параметры Ðабор параметров командной Ñтроки, необходимых\n\ + пакетному файлу." -STRING_CD_HELP, "Âûâîä èìåíè ëèáî ñìåíà òåêóùåãî êàòàëîãà.\n\n\ -CHDIR [/D][äèñê:][ïóòü]\n\ +STRING_CD_HELP, "Вывод имени либо Ñмена текущего каталога.\n\n\ +CHDIR [/D][диÑк:][путь]\n\ CHDIR[..|.]\n\ -CD [/D][äèñê:][ïóòü]\n\ +CD [/D][диÑк:][путь]\n\ CD[..|.]\n\n\ - .. îáîçíà÷àåò ðîäèòåëüñêèé êàòàëîã\n\ - . îáîçíà÷àåò òåêóùèé êàòàëîã\n\ - /D Îäíîâðåìåííàÿ ñìåíà òåêóùèõ äèñêà è êàòàëîãà.\n\n\ -Êîìàíäà CD äèñê: îòîáðàæàåò èìÿ òåêóùåãî êàòàëîãà óêàçàííîãî äèñêà.\n\ -Êîìàíäà CD áåç ïàðàìåòðîâ îòîáðàæàåò èìåíà òåêóùèõ äèñêà è êàòàëîãà.\n" + .. обозначает родительÑкий каталог\n\ + . обозначает текущий каталог\n\ + /D ÐžÐ´Ð½Ð¾Ð²Ñ€ÐµÐ¼ÐµÐ½Ð½Ð°Ñ Ñмена текущих диÑка и каталога.\n\n\ +Команда CD диÑк: отображает Ð¸Ð¼Ñ Ñ‚ÐµÐºÑƒÑ‰ÐµÐ³Ð¾ каталога указанного диÑка.\n\ +Команда CD без параметров отображает имена текущих диÑка и каталога.\n" -STRING_CHCP_HELP, "Âûâîä èëè ñìåíà òåêóùåãî íîìåðà êîäîâîé ñòðàíèöû.\n\n\ +STRING_CHCP_HELP, "Вывод или Ñмена текущего номера кодовой Ñтраницы.\n\n\ CHCP [nnn]\n\n\ - nnn Ãîìåð êîäîâîé ñòðàíèöû.\n\n\ -Êîìàíäà CHCP áåç ïàðàìåòðà âûâîäèò òåêóùèé íîìåð êîäîâîé ñòðàíèöû.\n" + nnn Ðомер кодовой Ñтраницы.\n\n\ +Команда CHCP без параметра выводит текущий номер кодовой Ñтраницы.\n" -STRING_CHOICE_HELP, "Æäåò, ïîêà ïîëüçîâàòåëü íå âûáåðåò îäèí èç óêàçàííûõ â ñïèñêå ñèìâîëîâ.\n\n\ -CHOICE [/C[:]ñïèñîê_ñèìâîëîâ][/N][/S][/T[:]c,nn][òåêñò]\n\n\ - /C[:]ñïèñîê_ñèìâîëîâ Óêàçûâàåò äîïóñòèìûå ñèìâîëû. Ãî óìîë÷àíèþ ýòî YN.\n\ - /N ÃÃ¥ âûâîäèòü ñïèñîê ñèìâîëîâ è ? ïîñëå ïîäñêàçêè.\n\ - /S Òðàêòîâàòü ñèìâîëû êàê ÷óâñòâèòåëüíûå ê ðåãèñòðó.\n\ - /T[:]c,nn Ãî óìîë÷àíèþ âûáîð c ïî èñòå÷åíèè nn ñåêóíä.\n\ - text Ãîäñêàçêà.\n\n\ -ERRORLEVEL óñòàíàâëèâàåòñÿ ðàâíûì íîìåðó âûáðàííîãî ñèìâîëà.\n" +STRING_CHOICE_HELP, "Ждет, пока пользователь не выберет один из указанных в ÑпиÑке Ñимволов.\n\n\ +CHOICE [/C[:]ÑпиÑок_Ñимволов][/N][/S][/T[:]c,nn][текÑÑ‚]\n\n\ + /C[:]ÑпиÑок_Ñимволов Указывает допуÑтимые Ñимволы. По умолчанию Ñто YN.\n\ + /N Ðе выводить ÑпиÑок Ñимволов и ? поÑле подÑказки.\n\ + /S Трактовать Ñимволы как чувÑтвительные к региÑтру.\n\ + /T[:]c,nn По умолчанию выбор c по иÑтечении nn Ñекунд.\n\ + text ПодÑказка.\n\n\ +ERRORLEVEL уÑтанавливаетÑÑ Ñ€Ð°Ð²Ð½Ñ‹Ð¼ номеру выбранного Ñимвола.\n" -STRING_CLS_HELP, "Î÷èñòêà ýêðàíà.\n\nCLS\n" +STRING_CLS_HELP, "ОчиÑтка Ñкрана.\n\nCLS\n" -STRING_CMD_HELP1, "\nÄîñòóïíûå âíóòðåííèå êîìàíäû:\n" +STRING_CMD_HELP1, "\nДоÑтупные внутренние команды:\n" -STRING_CMD_HELP2, "\nÄîñòóïíûå âîçìîæíîñòè:" +STRING_CMD_HELP2, "\nДоÑтупные возможноÑти:" -STRING_CMD_HELP3," [ïñåâäîíèìû]" +STRING_CMD_HELP3," [пÑевдонимы]" -STRING_CMD_HELP4," [èñòîðèÿ]" +STRING_CMD_HELP4," [иÑториÑ]" -STRING_CMD_HELP5," [çàâåðøåíèå èìåí ôàéëîâ unix]" +STRING_CMD_HELP5," [завершение имен файлов unix]" -STRING_CMD_HELP6," [ñòåê äèðåêòîðèé]" +STRING_CMD_HELP6," [Ñтек директорий]" -STRING_CMD_HELP7," [ïåðåíàïðàâëåíèå è piping]" +STRING_CMD_HELP7," [перенаправление и piping]" -STRING_CMD_HELP8, "Çàïóñê íîâîé êîïèè èíòåðïðåòàòîðà êîìàíä ReactOS.\n\n\ -CMD [/[C|K] êîìàíäà][/P][/Q][/T:bf]\n\n\ - /C êîìàíäà Âûïîëíåíèå óêàçàííîé êîìàíäû ñ ïîñëåäóþùèì çàâåðøåíèåì.\n\ - /K êîìàíäà Âûïîëíåíèå óêàçàííîé êîìàíäû áåç ïîñëåäóþùåãî çàâåðøåíèÿ.\n\ - /P CMD ñòàíîâèòñÿ ïåðìàíåíòíûì è çàïóñêàåò autoexec.bat\n\ - (ïðîöåññ íåìîæåò áûòü çàâåðøåí).\n\ - /T:öâ Âûáîð öâåòà òåêñòà/ôîíà (áîëåå ïîäðîáíî ñì. COLOR /?).\n" +STRING_CMD_HELP8, "ЗапуÑк новой копии интерпретатора команд ReactOS.\n\n\ +CMD [/[C|K] команда][/P][/Q][/T:bf]\n\n\ + /C команда Выполнение указанной команды Ñ Ð¿Ð¾Ñледующим завершением.\n\ + /K команда Выполнение указанной команды без поÑледующего завершениÑ.\n\ + /P CMD ÑтановитÑÑ Ð¿ÐµÑ€Ð¼Ð°Ð½ÐµÐ½Ñ‚Ð½Ñ‹Ð¼ и запуÑкает autoexec.bat\n\ + (процеÑÑ Ð½ÐµÐ¼Ð¾Ð¶ÐµÑ‚ быть завершен).\n\ + /T:цв Выбор цвета текÑта/фона (более подробно Ñм. COLOR /?).\n" -STRING_COLOR_HELP1, "Óñòàíîâêà öâåòîâ ïî óìîë÷àíèþ äëÿ òåêñòà è ôîíà.\n\n\ -COLOR [öâåòà [/-F]] \n\n\ - öâåòà Àòðèáóòû öâåòîâ äëÿ òåêñòîâûõ îêîí\n\ - /-F ÃÃ¥ çàëèâàòü íåçàïîëíåííûå ìåñòà öâåòîì\n\n\ -Åñòü òðè ñïîñîáà îáîçíà÷àòü öâåòà:\n\ -1) ïî íàçâàíèþ íà àíãëèéñêîì ÿçûêå (òðåáóþòñÿ òîëüêî ïåðâûå òðè áóêâû öâåòà)\n\ -2) â âèäå äåñÿòè÷íûõ ÷èñåë (decimal on decimal)\n\ -3) äâà øåñòíàäöàòåðè÷íûõ ÷èñëà\n\n\ -Òàáëèöà öâåòîâ:\n\ -äåñ. øåñò.íàçâàíèå äåñ. øåñò.íàçâàíèå\n\ - 0 0 = ×åðíûé 8 8 = Ñåðûé\n\ - 1 1 = Ñèíèé 9 9 = Ñâåòëî-ñèíèé\n\ - 2 2 = Çåëåíûé 10 A = Ñâåòëî-çåëåíûé\n\ - 3 3 = Ãîëóáîé 11 B = Ñâåòëî-ãîëóáîé\n\ - 4 4 = Êðàñíûé 12 C = Ñâåòëî-êðàñíûé\n\ - 5 5 = Ëèëîâûé 13 D = Ñâåòëî-ëèëîâûé\n\ - 6 6 = Æåëòûé 14 E = Ñâåòëî-æåëòûé\n\ - 7 7 = Ãåëûé 15 F = ßðêî-áåëûé\n" +STRING_COLOR_HELP1, "УÑтановка цветов по умолчанию Ð´Ð»Ñ Ñ‚ÐµÐºÑта и фона.\n\n\ +COLOR [цвета [/-F]] \n\n\ + цвета Ðтрибуты цветов Ð´Ð»Ñ Ñ‚ÐµÐºÑтовых окон\n\ + /-F Ðе заливать незаполненные меÑта цветом\n\n\ +ЕÑть три ÑпоÑоба обозначать цвета:\n\ +1) по названию на английÑком Ñзыке (требуютÑÑ Ñ‚Ð¾Ð»ÑŒÐºÐ¾ первые три буквы цвета)\n\ +2) в виде деÑÑтичных чиÑел (decimal on decimal)\n\ +3) два шеÑтнадцатеричных чиÑла\n\n\ +Таблица цветов:\n\ +деÑ. шеÑÑ‚.название деÑ. шеÑÑ‚.название\n\ + 0 0 = Черный 8 8 = Серый\n\ + 1 1 = Синий 9 9 = Светло-Ñиний\n\ + 2 2 = Зеленый 10 A = Светло-зеленый\n\ + 3 3 = Голубой 11 B = Светло-голубой\n\ + 4 4 = КраÑный 12 C = Светло-краÑный\n\ + 5 5 = Лиловый 13 D = Светло-лиловый\n\ + 6 6 = Желтый 14 E = Светло-желтый\n\ + 7 7 = Белый 15 F = Ярко-белый\n" -STRING_COPY_HELP1, "Ãåðåçàïèñàòü %s (Yes/No/All)? " +STRING_COPY_HELP1, "ПерезапиÑать %s (Yes/No/All)? " -STRING_COPY_HELP2, "Êîïèðîâàíèå îäíîãî èëè íåñêîëüêèõ ôàéëîâ â äðóãîå ìåñòî.\n\n\ -COPY [/V][/Y|/-Y][/A|/B] èñòî÷íèê [/A|/B]\n\ - [+ èñòî÷íèê [/A|/B] [+ ...]] [ðåçóëüòàò [/A|/B]]\n\n\ - èñòî÷íèê Èìåíà îäíîãî èëè íåñêîëüêèõ êîïèðóåìûõ ôàéëîâ.\n\ - /A Ôàéë ÿâëÿåòñÿ òåêñòîâûì ôàéëîì ASCII.\n\ - /B Ôàéë ÿâëÿåòñÿ äâîè÷íûì ôàéëîì.\n\ - ðåçóëüòàò Êàòàëîã è/èëè èìÿ äëÿ êîíå÷íûõ ôàéëîâ.\n\ - /V Ãðîâåðêà ïðàâèëüíîñòè êîïèðîâàíèÿ ôàéëîâ.\n\ - /Y Ãîäàâëåíèå çàïðîñà ïîäòâåðæäåíèÿ íà ïåðåçàïèñü ñóùåñòâóþùåãî\n\ - ðåçóëüòèðóþùåãî ôàéëà.\n\ - /-Y Îáÿçàòåëüíûé çàïðîñ ïîäòâåðæäåíèÿ íà ïåðåçàïèñü ñóùåñòâóþùåãî\n\ - ðåçóëüòèðóþùåãî ôàéëà.\n\n\ -Êëþ÷ /Y ìîæíî óñòàíîâèòü ÷åðåç ïåðåìåííóþ ñðåäû COPYCMD.\n\ +STRING_COPY_HELP2, "Копирование одного или неÑкольких файлов в другое меÑто.\n\n\ +COPY [/V][/Y|/-Y][/A|/B] иÑточник [/A|/B]\n\ + [+ иÑточник [/A|/B] [+ ...]] [результат [/A|/B]]\n\n\ + иÑточник Имена одного или неÑкольких копируемых файлов.\n\ + /A Файл ÑвлÑетÑÑ Ñ‚ÐµÐºÑтовым файлом ASCII.\n\ + /B Файл ÑвлÑетÑÑ Ð´Ð²Ð¾Ð¸Ñ‡Ð½Ñ‹Ð¼ файлом.\n\ + результат Каталог и/или Ð¸Ð¼Ñ Ð´Ð»Ñ ÐºÐ¾Ð½ÐµÑ‡Ð½Ñ‹Ñ… файлов.\n\ + /V Проверка правильноÑти ÐºÐ¾Ð¿Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ñ„Ð°Ð¹Ð»Ð¾Ð².\n\ + /Y Подавление запроÑа Ð¿Ð¾Ð´Ñ‚Ð²ÐµÑ€Ð¶Ð´ÐµÐ½Ð¸Ñ Ð½Ð° перезапиÑÑŒ ÑущеÑтвующего\n\ + результирующего файла.\n\ + /-Y ОбÑзательный Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð¿Ð¾Ð´Ñ‚Ð²ÐµÑ€Ð¶Ð´ÐµÐ½Ð¸Ñ Ð½Ð° перезапиÑÑŒ ÑущеÑтвующего\n\ + результирующего файла.\n\n\ +Ключ /Y можно уÑтановить через переменную Ñреды COPYCMD.\n\ ...\n" -STRING_DATE_HELP1, "\nÂâåäèòå íîâóþ äàòó (ìì%cää%cãããã): " +STRING_DATE_HELP1, "\nВведите новую дату (мм%cдд%cгггг): " -STRING_DATE_HELP2, "\nÂâåäèòå íîâóþ äàòó (ää%cìì%cãããã): " +STRING_DATE_HELP2, "\nВведите новую дату (дд%cмм%cгггг): " -STRING_DATE_HELP3, "\nÂâåäèòå íîâóþ äàòó (ãããã%cìì%cää): " +STRING_DATE_HELP3, "\nВведите новую дату (гггг%cмм%cдд): " -STRING_DATE_HELP4, "Âûâîä èëè èçìåíåíèå äàòû.\n\n\ -DATE [/T][äàòà]\n\n\ - /T ÃÃ¥ çàïðàøèâàòü ââîä íîâîé äàòû\n\n\ -Êîìàíäà DATE áåç ïàðàìåòðîâ îòîáðàæàåò òåêóùóþ äàòó è çàïðàøèâàåò ââîä\n\ -íîâîé äàòû. Äëÿ ñîõðàíåíèÿ òåêóùåé äàòû íàæìèòå êëàâèøó ENTER.\n" +STRING_DATE_HELP4, "Вывод или изменение даты.\n\n\ +DATE [/T][дата]\n\n\ + /T Ðе запрашивать ввод новой даты\n\n\ +Команда DATE без параметров отображает текущую дату и запрашивает ввод\n\ +новой даты. Ð”Ð»Ñ ÑÐ¾Ñ…Ñ€Ð°Ð½ÐµÐ½Ð¸Ñ Ñ‚ÐµÐºÑƒÑ‰ÐµÐ¹ даты нажмите клавишу ENTER.\n" -STRING_DEL_HELP1, "Óäàëåíèå îäíîãî èëè íåñêîëüêèõ ôàéëîâ.\n\n\ -DEL [/N /P /T /Q /S /W /Y /Z /A[[:]àòðèáóòû]] èìåíà_ôàéëîâ ...\n\ -DELETE [/N /P /T /Q /S /W /Y /Z /A[[:]àòðèáóòû]] èìåíà_ôàéëîâ ...\n\ -ERASE [/N /P /T /Q /S /W /Y /Z /A[[:]àòðèáóòû]] èìåíà_ôàéëîâ ...\n\n\ - èìåíà_ôàéëîâ Èìåíà îäíîãî èëè íåñêîëüêèõ ôàéëîâ.\n\n\ - /N Ãåâûïîëíÿòü íåïîñðåäñòâåííî îïåðàöèþ óäàëåíèÿ ôàéëà.\n\ - /P Çàïðîñ íà ïîäòâåðæäåíèå ïåðåä óäàëåíèåì êàæäîãî ôàéëà.\n\ - /T Ãîêàçûâàåò êîëè÷åñòâî óäàëåííûõ ôàéëîâ è îñâîáîäèâøåãîñÿ\n\ - äèñêîâîãî ïðîñòðàíñòâà.\n\ - /Q Îòêëþ÷åíèå çàïðîñà íà ïîäòâåðæäåíèå ïðè óäàëåíèè ôàéëîâ.\n\ - /W Ãåðåïèñàòü ôàéë ñëó÷àéíûìè äàííûìè ïåðåä óäàëåíèåì.\n\ - /Y Îòêëþ÷åíèå çàïðîñà íà ïîäòâåðæäåíèå ïðè óäàëåíèè ôàéëîâ\n\ - äàæå äëÿ ìàñêè *.*.\n\ - /F Ãðèíóäèòåëüíîå óäàëåíèå ôàéëîâ, äîñòóïíûõ òîëüêî äëÿ ÷òåíèÿ.\n\ - /S Óäàëÿòü ôàéë èç âñåõ ïîääèðåêòîðèé\n\ - /A Îòáîð ôàéëîâ äëÿ óäàëåíèÿ ïî àòðèáóòàì.\n\ - R Äîñòóïíûé òîëüêî äëÿ ÷òåíèÿ\n\ - S Ñèñòåìíûå ôàéëû\n\ - A Ôàéëû äëÿ àðõèâèðîâàíèÿ\n\ - H Ñêðûòûå ôàéëû\n\ - Ãðåôèêñ ""-"" èìååò çíà÷åíèå ÃÃ…\n" +STRING_DEL_HELP1, "Удаление одного или неÑкольких файлов.\n\n\ +DEL [/N /P /T /Q /S /W /Y /Z /A[[:]атрибуты]] имена_файлов ...\n\ +DELETE [/N /P /T /Q /S /W /Y /Z /A[[:]атрибуты]] имена_файлов ...\n\ +ERASE [/N /P /T /Q /S /W /Y /Z /A[[:]атрибуты]] имена_файлов ...\n\n\ + имена_файлов Имена одного или неÑкольких файлов.\n\n\ + /N ÐевыполнÑть непоÑредÑтвенно операцию ÑƒÐ´Ð°Ð»ÐµÐ½Ð¸Ñ Ñ„Ð°Ð¹Ð»Ð°.\n\ + /P Ð—Ð°Ð¿Ñ€Ð¾Ñ Ð½Ð° подтверждение перед удалением каждого файла.\n\ + /T Показывает количеÑтво удаленных файлов и оÑвободившегоÑÑ\n\ + диÑкового проÑтранÑтва.\n\ + /Q Отключение запроÑа на подтверждение при удалении файлов.\n\ + /W ПерепиÑать файл Ñлучайными данными перед удалением.\n\ + /Y Отключение запроÑа на подтверждение при удалении файлов\n\ + даже Ð´Ð»Ñ Ð¼Ð°Ñки *.*.\n\ + /F Принудительное удаление файлов, доÑтупных только Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ.\n\ + /S УдалÑть файл из вÑех поддиректорий\n\ + /A Отбор файлов Ð´Ð»Ñ ÑƒÐ´Ð°Ð»ÐµÐ½Ð¸Ñ Ð¿Ð¾ атрибутам.\n\ + R ДоÑтупный только Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ\n\ + S СиÑтемные файлы\n\ + A Файлы Ð´Ð»Ñ Ð°Ñ€Ñ…Ð¸Ð²Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ\n\ + H Скрытые файлы\n\ + ÐŸÑ€ÐµÑ„Ð¸ÐºÑ ""-"" имеет значение ÐЕ\n" -STRING_DEL_HELP2, "Âñå ôàéëû â êàòàëîãå áóäóò óäàëåíû!\nÂû óâåðåíû (Y/N)?" -STRING_DEL_HELP3, " %lu ôàéë óäàëåí\n" -STRING_DEL_HELP4, " %lu ôàéëîâ óäàëåíî\n" +STRING_DEL_HELP2, "Ð’Ñе файлы в каталоге будут удалены!\nÐ’Ñ‹ уверены (Y/N)?" +STRING_DEL_HELP3, " %lu файл удален\n" +STRING_DEL_HELP4, " %lu файлов удалено\n" -STRING_DELAY_HELP, "ïàóçà íà n ñåêóíä èëè ìèëëèñåêóíä\n\ +STRING_DELAY_HELP, "пауза на n Ñекунд или миллиÑекунд\n\ DELAY [/m]n\n\n\ - /m óêàçûâàåò, ÷òî n îçíà÷àåò êîëè÷åñòâî ìèëëèñåêóíä\n\ - èíà÷å n îçíà÷àåò êîëè÷åñòâî ñåêóíä\n" + /m указывает, что n означает количеÑтво миллиÑекунд\n\ + иначе n означает количеÑтво Ñекунд\n" -STRING_DIR_HELP1, "DIR [äèñê:][ïóòü][èìÿ_ôàéëà] [/A[[:]àòðèáóòû]] [/B] [/C] [/D] [/L] [/N]\n\ +STRING_DIR_HELP1, "DIR [диÑк:][путь][имÑ_файла] [/A[[:]атрибуты]] [/B] [/C] [/D] [/L] [/N]\n\ [/O[[:]sortorder]] [/P] [/Q] [/S] [/T[[:]timefield]] [/W] [/X] [/4]\n\n\ - [äèñê:][ïóòü][èìÿ_ôàéëà]\n\ - Äèñê, êàòàëîã è/èëè ôàéëû, êîòîðûå ñëåäóåò âêëþ÷èòü â ñïèñîê.\n\n\ - /A Âûâîä ôàéëîâ ñ óêàçàííûìè àòðèáóòàìè.\n\ - àòðèáóòû D Êàòàëîãè R Äîñòóïíûå òîëüêî äëÿ ÷òåíèÿ\n\ - H Ñêðûòûå ôàéëû A Ôàéëû äëÿ àðõèâèðîâàíèÿ\n\ - S Ñèñòåìíûå ôàéëû Ãðåôèêñ ""-"" èìååò çíà÷åíèå ÃÃ…\n\ - /B Âûâîä òîëüêî èìåí ôàéëîâ.\n\ - /C Ãðèìåíåíèå ðàçäåëèòåëÿ ãðóïï ðàçðÿäîâ äëÿ âûâîäà ðàçìåðîâ ôàéëîâ\n\ - (ïî óìîë÷àíèþ). Äëÿ îòêëþ÷åíèÿ ýòîãî ðåæèìà ñëóæèò êëþ÷ /-C.\n\ - /D Âûâîä ñïèñêà â íåñêîëüêî ñòîëáöîâ ñ ñîðòèðîâêîé ïî ñòîëáöàì.\n\ - /L Èñïîëüçîâàíèå íèæíåãî ðåãèñòðà äëÿ èìåí ôàéëîâ.\n\ - /N Îòîáðàæåíèå èìåí ôàéëîâ â êðàéíåì ïðàâîì ñòîëáöå.\n\ - /O Ñîðòèðîâêà ñïèñêà îòîáðàæàåìûõ ôàéëîâ.\n\ - ïîðÿäîê N Ãî èìåíè (àëôàâèòíàÿ) S Ãî ðàçìåðó (ñïåðâà ìåíüøèå)\n\ - E Ãî ðàñøèðåíèþ (àëôàâèòíàÿ) D Ãî äàòå (ñïåðâà áîëåå ñòàðûå)\n\ - G Ãà÷àòü ñïèñîê ñ êàòàëîãîâ Ãðåôèêñ ""-"" îáðàùàåò ïîðÿäîê\n\ - /P Ãàóçà ïîñëå çàïîëíåíèÿ êàæäîãî ýêðàíà.\n\ - /Q Âûâîä ñâåäåíèé î âëàäåëüöå ôàéëà.\n\ - /S Âûâîä ñïèñêà ôàéëîâ èç óêàçàííîãî êàòàëîãà è åãî ïîäêàòàëîãîâ.\n\ - /T Âûáîð ïîëÿ âðåìåíè äëÿ îòîáðàæåíèÿ è ñîðòèðîâêè\n\ - âðåìÿ C Ñîçäàíèå\n\ - A Ãîñëåäíåå èñïîëüçîâàíèå\n\ - W Ãîñëåäíåå èçìåíåíèå\n\ - /W Âûâîä ñïèñêà â íåñêîëüêî ñòîëáöîâ.\n\ - /X Îòîáðàæåíèå êîðîòêèõ èìåí äëÿ ôàéëîâ, ÷üè èìåíà íå ñîîòâåòñòâóþò\n\ - ñòàíäàðòó 8.3. Ôîðìàò àíàëîãè÷åí âûâîäó ñ êëþ÷îì /N, íî êîðîòêèå\n\ - èìåíà ôàéëîâ âûâîäÿòñÿ ñëåâà îò äëèííûõ. Åñëè êîðîòêîãî èìåíè ó\n\ - ôàéëà íåò, âìåñòî íåãî âûâîäÿòñÿ ïðîáåëû.\n\ - /4 Âûâîä íîìåðà ãîäà â ÷åòûðåõçíà÷íîì ôîðìàòå\n" + [диÑк:][путь][имÑ_файла]\n\ + ДиÑк, каталог и/или файлы, которые Ñледует включить в ÑпиÑок.\n\n\ + /A Вывод файлов Ñ ÑƒÐºÐ°Ð·Ð°Ð½Ð½Ñ‹Ð¼Ð¸ атрибутами.\n\ + атрибуты D Каталоги R ДоÑтупные только Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ\n\ + H Скрытые файлы A Файлы Ð´Ð»Ñ Ð°Ñ€Ñ…Ð¸Ð²Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ\n\ + S СиÑтемные файлы ÐŸÑ€ÐµÑ„Ð¸ÐºÑ ""-"" имеет значение ÐЕ\n\ + /B Вывод только имен файлов.\n\ + /C Применение Ñ€Ð°Ð·Ð´ÐµÐ»Ð¸Ñ‚ÐµÐ»Ñ Ð³Ñ€ÑƒÐ¿Ð¿ разрÑдов Ð´Ð»Ñ Ð²Ñ‹Ð²Ð¾Ð´Ð° размеров файлов\n\ + (по умолчанию). Ð”Ð»Ñ Ð¾Ñ‚ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ñтого режима Ñлужит ключ /-C.\n\ + /D Вывод ÑпиÑка в неÑколько Ñтолбцов Ñ Ñортировкой по Ñтолбцам.\n\ + /L ИÑпользование нижнего региÑтра Ð´Ð»Ñ Ð¸Ð¼ÐµÐ½ файлов.\n\ + /N Отображение имен файлов в крайнем правом Ñтолбце.\n\ + /O Сортировка ÑпиÑка отображаемых файлов.\n\ + порÑдок N По имени (алфавитнаÑ) S По размеру (Ñперва меньшие)\n\ + E По раÑширению (алфавитнаÑ) D По дате (Ñперва более Ñтарые)\n\ + G Ðачать ÑпиÑок Ñ ÐºÐ°Ñ‚Ð°Ð»Ð¾Ð³Ð¾Ð² ÐŸÑ€ÐµÑ„Ð¸ÐºÑ ""-"" обращает порÑдок\n\ + /P Пауза поÑле Ð·Ð°Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ ÐºÐ°Ð¶Ð´Ð¾Ð³Ð¾ Ñкрана.\n\ + /Q Вывод Ñведений о владельце файла.\n\ + /S Вывод ÑпиÑка файлов из указанного каталога и его подкаталогов.\n\ + /T Выбор Ð¿Ð¾Ð»Ñ Ð²Ñ€ÐµÐ¼ÐµÐ½Ð¸ Ð´Ð»Ñ Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð¸ Ñортировки\n\ + Ð²Ñ€ÐµÐ¼Ñ C Создание\n\ + A ПоÑледнее иÑпользование\n\ + W ПоÑледнее изменение\n\ + /W Вывод ÑпиÑка в неÑколько Ñтолбцов.\n\ + /X Отображение коротких имен Ð´Ð»Ñ Ñ„Ð°Ð¹Ð»Ð¾Ð², чьи имена не ÑоответÑтвуют\n\ + Ñтандарту 8.3. Формат аналогичен выводу Ñ ÐºÐ»ÑŽÑ‡Ð¾Ð¼ /N, но короткие\n\ + имена файлов выводÑÑ‚ÑÑ Ñлева от длинных. ЕÑли короткого имени у\n\ + файла нет, вмеÑто него выводÑÑ‚ÑÑ Ð¿Ñ€Ð¾Ð±ÐµÐ»Ñ‹.\n\ + /4 Вывод номера года в четырехзначном формате\n" -STRING_DIR_HELP2, " Òîì â óñòðîéñòâå %c èìååò ìåòêó %s\n" -STRING_DIR_HELP3, " Òîì â óñòðîéñòâå %c íå èìååò ìåòêè.\n" -STRING_DIR_HELP4, " Ñåðèéíûé íîìåð òîìà: %04X-%04X\n" -STRING_DIR_HELP5, "\n Âñåãî:\n%16i Ôàéë(îâ)% 14s áàéò\n" -STRING_DIR_HELP6, "%16i Dir(s)% 15s áàéò\n" -STRING_DIR_HELP7, "\n Êàòàëîã of %s\n\n" -STRING_DIR_HELP8, "%16i ôàéë(îâ)% 14s áàéò\n" +STRING_DIR_HELP2, " Том в уÑтройÑтве %c имеет метку %s\n" +STRING_DIR_HELP3, " Том в уÑтройÑтве %c не имеет метки.\n" +STRING_DIR_HELP4, " Серийный номер тома: %04X-%04X\n" +STRING_DIR_HELP5, "\n Ð’Ñего:\n%16i Файл(ов)% 14s байт\n" +STRING_DIR_HELP6, "%16i Dir(s)% 15s байт\n" +STRING_DIR_HELP7, "\n Каталог of %s\n\n" +STRING_DIR_HELP8, "%16i файл(ов)% 14s байт\n" -STRING_DIRSTACK_HELP1, "Ñîõðàíÿåò òåêóùóþ äèðåêòîðèþ äëÿ èñïîëüçîâàíèÿ êîìàíäîé POPD, çàòåì\n\ -èçìåíÿåò åå íà óêàçàííóþ.\n\n\ +STRING_DIRSTACK_HELP1, "СохранÑет текущую директорию Ð´Ð»Ñ Ð¸ÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð¾Ð¹ POPD, затем\n\ +изменÑет ее на указанную.\n\n\ PUSHD [path | ..]\n\n\ - path Óêàçûâàåò äèðåêòîðèþ, êîòîðóþ íàäî ñäåëàòü òåêóùåé\n" + path Указывает директорию, которую надо Ñделать текущей\n" -STRING_DIRSTACK_HELP2, "Èçìåíÿåò òåêóùóþ äèðåêòîðèþ íà òó, êîòîðàÿ ñîõðàíåíà êîìàíäîé PUSHD.\n\nPOPD" +STRING_DIRSTACK_HELP2, "ИзменÑет текущую директорию на ту, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ñохранена командой PUSHD.\n\nPOPD" -STRING_DIRSTACK_HELP3, "Ãå÷àòàåò ñîäåðæèìîå ñòåêà äèðåêòîðèé.\n\nDIRS" +STRING_DIRSTACK_HELP3, "Печатает Ñодержимое Ñтека директорий.\n\nDIRS" -STRING_DIRSTACK_HELP4, "Ñòåê äèðåêòîðèé ïóñò" +STRING_DIRSTACK_HELP4, "Стек директорий пуÑÑ‚" -STRING_ECHO_HELP1, "Âûäàåò ñîîáùåíèå áåç ïåðåâîäà ñòðîêè.\n\n\ +STRING_ECHO_HELP1, "Выдает Ñообщение без перевода Ñтроки.\n\n\ ECHOS message" -STRING_ECHO_HELP2, "Âûäàåò ñîîáùåíèå â ñòàíäàðòíûé êàíàë âûâîäà îøèáîê.\n\n\ +STRING_ECHO_HELP2, "Выдает Ñообщение в Ñтандартный канал вывода ошибок.\n\n\ ECHOERR message\n\ - ECHOERR. ïå÷àòàåò ïóñòóþ ñòðîêó" + ECHOERR. печатает пуÑтую Ñтроку" -STRING_ECHO_HELP3, "Ãå÷àòàåò ñîîáùåíèå â ñòàíäàðòíûé êàíàë âûâîäà îøèáîê áåç ïåðåâîäà ñòðîêè è âîçâðàòà êàðåòêè.\n\n\ +STRING_ECHO_HELP3, "Печатает Ñообщение в Ñтандартный канал вывода ошибок без перевода Ñтроки и возврата каретки.\n\n\ ECHOSERR message" -STRING_ECHO_HELP4, "Âûâîä ñîîáùåíèé è ïåðåêëþ÷åíèå ðåæèìà îòîáðàæåíèÿ êîìàíä íà ýêðàíå.\n\n\ +STRING_ECHO_HELP4, "Вывод Ñообщений и переключение режима Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´ на Ñкране.\n\n\ ECHO [ON | OFF]\n\ - ECHO [ñîîáùåíèå]\n\ - ECHO. âûâîä ïóñòîé ñòðîêè\n\n\ -ECHO áåç ïàðàìåòðà âûâîäèò òåêóùèé ðåæèì îòîáðàæåíèÿ êîìàíä." + ECHO [Ñообщение]\n\ + ECHO. вывод пуÑтой Ñтроки\n\n\ +ECHO без параметра выводит текущий режим Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´." STRING_ECHO_HELP5, "ECHO is %s\n" -STRING_EXIT_HELP, "Çàâåðøàåò èíòåðïðåòàòîð êîìàíä.\n\nEXIT\n" +STRING_EXIT_HELP, "Завершает интерпретатор команд.\n\nEXIT\n" -STRING_FOR_HELP1, "Çàïóñêàåò óêàçàííóþ êîìàíäó äëÿ êàæäîãî ôàéëà èç íàáîðà ôàéëîâ\n\n\ -FOR %ïåðåìåííàÿ IN (íàáîð) DO êîìàíäà [ïàðàìåòðû]\n\n\ - %ïåðåìåííàÿ Ãîäñòàâëÿåìûé ïàðàìåòð.\n\ - (íàáîð) Ãàáîð èç îäíîãî èëè íåñêîëüêèõ ôàéëîâ.\n\ - Äîïóñêàåòñÿ èñïîëüçîâàíèå ïîäñòàíîâî÷íûõ çíàêîâ.\n\ - êîìàíäà Êîìàíäà, êîòîðóþ ñëåäóåò âûïîëíèòü äëÿ êàæäîãî ôàéëà.\n\ - ïàðàìåòðû Ãàðàìåòðû è êëþ÷è äëÿ óêàçàííîé êîìàíäû.\n\n\ - ïàêåòíûõ ôàéëàõ äëÿ êîìàíäû FOR èñïîëüçóåòñÿ çàïèñü\n\ -%%ïåðåìåííàÿ âìåñòî %ïåðåìåííàÿ.\n" +STRING_FOR_HELP1, "ЗапуÑкает указанную команду Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð³Ð¾ файла из набора файлов\n\n\ +FOR %Ð¿ÐµÑ€ÐµÐ¼ÐµÐ½Ð½Ð°Ñ IN (набор) DO команда [параметры]\n\n\ + %Ð¿ÐµÑ€ÐµÐ¼ÐµÐ½Ð½Ð°Ñ ÐŸÐ¾Ð´ÑтавлÑемый параметр.\n\ + (набор) Ðабор из одного или неÑкольких файлов.\n\ + ДопуÑкаетÑÑ Ð¸Ñпользование подÑтановочных знаков.\n\ + команда Команда, которую Ñледует выполнить Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð³Ð¾ файла.\n\ + параметры Параметры и ключи Ð´Ð»Ñ ÑƒÐºÐ°Ð·Ð°Ð½Ð½Ð¾Ð¹ команды.\n\n\ +Ð’ пакетных файлах Ð´Ð»Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ‹ FOR иÑпользуетÑÑ Ð·Ð°Ð¿Ð¸ÑÑŒ\n\ +%%Ð¿ÐµÑ€ÐµÐ¼ÐµÐ½Ð½Ð°Ñ Ð²Ð¼ÐµÑто %переменнаÑ.\n" -STRING_FREE_HELP1, "\nÒîì äèñêà %s: %-11s\n\ - Ñåðèéíûé íîìåð: %s\n\ - %16s áàéò îáùåãî äèñêîâîãî ïðîñòðàíñòâà\n\ - %16s áàéò çàíÿòî\n\ - %16s áàéò ñâîáîäíî\n" +STRING_FREE_HELP1, "\nТом диÑка %s: %-11s\n\ + Серийный номер: %s\n\ + %16s байт общего диÑкового проÑтранÑтва\n\ + %16s байт занÑто\n\ + %16s байт Ñвободно\n" -STRING_FREE_HELP2, "Âûâîäèò èíôîðìàöèþ î òîìå.\n\nFREE [drive: ...]\n" +STRING_FREE_HELP2, "Выводит информацию о томе.\n\nFREE [drive: ...]\n" -STRING_IF_HELP1, "Îïåðàòîð óñëîâíîãî âûïîëíåíèÿ êîìàíä â ïàêåòíîì ôàéëå.\n\n\ - IF [NOT] ERRORLEVEL ÷èñëî êîìàíäà\n\ - IF [NOT] ñòðîêà1==ñòðîêà2 êîìàíäà\n\ - IF [NOT] EXIST èìÿ_ôàéëà êîìàíäà\n\ - IF [NOT] DEFINED ïåðåìåííàÿ êîìàíäà\n\n\ - NOT Îáðàùàåò èñòèííîñòü óñëîâèÿ: èñòèííîå óñëîâèå\n\ - ñòàíîâèòñÿ ëîæíûì, à ëîæíîå - èñòèííûì.\n\ - ERRORLEVEL ÷èñëî Óñëîâèå ÿâëÿåòñÿ èñòèííûì, åñëè êîä âîçâðàòà ïîñëåäíåé\n\ - âûïîëíåííîé ïðîãðàììû íå ìåíüøå óêàçàííîãî ÷èñëà.\n\ - ñòðîêà1==ñòðîêà2 Ãòî óñëîâèå ÿâëÿåòñÿ èñòèííûì, åñëè óêàçàííûå ñòðîêè\n\ - ñîâïàäàþò.\n\ - EXIST èìÿ_ôàéëà Ãòî óñëîâèå ÿâëÿåòñÿ èñòèííûì, åñëè ôàéë ñ óêàçàííûì\n\ - èìåíåì ñóùåñòâóåò.\n\ -DEFINED ïåðåìåííàÿ Ãòî óñëîâèå ÿâëÿåòñÿ èñòèííûì, åñëè óêàçàííàÿ ïåðåìåííàÿ\n\ - çàäàíà\n\ - êîìàíäà Çàäàåò êîìàíäó, âûïîëíÿåìóþ ïðè èñòèííîñòè óñëîâèÿ.\n\ - Çà ýòîé êîìàíäîé ìîæåò ñëåäîâàòü êëþ÷åâîå ñëîâî ELSE,\n\ - ñëóæàùåå äëÿ óêàçàíèÿ êîìàíäû, êîòîðàÿ äîëæíà\n\ - âûïîëíÿòüñÿ â òîì ñëó÷àå, åñëè óñëîâèå ëîæíî.\n" +STRING_IF_HELP1, "Оператор уÑловного Ð²Ñ‹Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´ в пакетном файле.\n\n\ + IF [NOT] ERRORLEVEL чиÑло команда\n\ + IF [NOT] Ñтрока1==Ñтрока2 команда\n\ + IF [NOT] EXIST имÑ_файла команда\n\ + IF [NOT] DEFINED Ð¿ÐµÑ€ÐµÐ¼ÐµÐ½Ð½Ð°Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð°\n\n\ + NOT Обращает иÑтинноÑть уÑловиÑ: иÑтинное уÑловие\n\ + ÑтановитÑÑ Ð»Ð¾Ð¶Ð½Ñ‹Ð¼, а ложное - иÑтинным.\n\ + ERRORLEVEL чиÑло УÑловие ÑвлÑетÑÑ Ð¸Ñтинным, еÑли код возврата поÑледней\n\ + выполненной программы не меньше указанного чиÑла.\n\ + Ñтрока1==Ñтрока2 Это уÑловие ÑвлÑетÑÑ Ð¸Ñтинным, еÑли указанные Ñтроки\n\ + Ñовпадают.\n\ + EXIST имÑ_файла Это уÑловие ÑвлÑетÑÑ Ð¸Ñтинным, еÑли файл Ñ ÑƒÐºÐ°Ð·Ð°Ð½Ð½Ñ‹Ð¼\n\ + именем ÑущеÑтвует.\n\ +DEFINED Ð¿ÐµÑ€ÐµÐ¼ÐµÐ½Ð½Ð°Ñ Ð­Ñ‚Ð¾ уÑловие ÑвлÑетÑÑ Ð¸Ñтинным, еÑли ÑƒÐºÐ°Ð·Ð°Ð½Ð½Ð°Ñ Ð¿ÐµÑ€ÐµÐ¼ÐµÐ½Ð½Ð°Ñ\n\ + задана\n\ + команда Задает команду, выполнÑемую при иÑтинноÑти уÑловиÑ.\n\ + За Ñтой командой может Ñледовать ключевое Ñлово ELSE,\n\ + Ñлужащее Ð´Ð»Ñ ÑƒÐºÐ°Ð·Ð°Ð½Ð¸Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ‹, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð´Ð¾Ð»Ð¶Ð½Ð°\n\ + выполнÑтьÑÑ Ð² том Ñлучае, еÑли уÑловие ложно.\n" -STRING_GOTO_HELP1, "Ãåðåäà÷à óïðàâëåíèÿ ñîäåðæàùåé ìåòêó ñòðîêå ïàêåòíîãî ôàéëà.\n\n\ -GOTO ìåòêà\n\n\ - label Ñòðîêà ïàêåòíîãî ôàéëà, îôîðìëåííàÿ êàê ìåòêà.\n\n\ -Ìåòêà äîëæíà íàõîäèòüñÿ â îòäåëüíîé ñòðîêå è íà÷èíàòüñÿ ñ äâîåòî÷èÿ." +STRING_GOTO_HELP1, "Передача ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ñодержащей метку Ñтроке пакетного файла.\n\n\ +GOTO метка\n\n\ + label Строка пакетного файла, Ð¾Ñ„Ð¾Ñ€Ð¼Ð»ÐµÐ½Ð½Ð°Ñ ÐºÐ°Ðº метка.\n\n\ +Метка должна находитьÑÑ Ð² отдельной Ñтроке и начинатьÑÑ Ñ Ð´Ð²Ð¾ÐµÑ‚Ð¾Ñ‡Ð¸Ñ." -STRING_LABEL_HELP1, "Ñîçäàíèå, èçìåíåíèå è óäàëåíèå ìåòîê òîìà.\n\nLABEL [äèñê:][ìåòêà]\n" +STRING_LABEL_HELP1, "Создание, изменение и удаление меток тома.\n\nLABEL [диÑк:][метка]\n" -STRING_LABEL_HELP2, "Òîì â óñòðîéñòâå %c èìååò ìåòêó %s\n" -STRING_LABEL_HELP3, "Òîì â óñòðîéñòâå %c: íå èìååò ìåòêè\n" -STRING_LABEL_HELP4, "Ñåðèéíûé íîìåð òîìà: %04X-%04X\n" -STRING_LABEL_HELP5, "Ìåòêà òîìà (11 áóêâ, ÂÂÎÄ äëÿ ïóñòîé ìåòêè)? " +STRING_LABEL_HELP2, "Том в уÑтройÑтве %c имеет метку %s\n" +STRING_LABEL_HELP3, "Том в уÑтройÑтве %c: не имеет метки\n" +STRING_LABEL_HELP4, "Серийный номер тома: %04X-%04X\n" +STRING_LABEL_HELP5, "Метка тома (11 букв, ВВОД Ð´Ð»Ñ Ð¿ÑƒÑтой метки)? " -STRING_LOCALE_HELP1, "Òåêóùåå âðåìÿ: " +STRING_LOCALE_HELP1, "Текущее времÑ: " -STRING_MKDIR_HELP, "Ñîçäàíèå êàòàëîãà.\n\n\ -MKDIR [äèñê:]ïóòü\nMD [äèñê:]ïóòü" +STRING_MKDIR_HELP, "Создание каталога.\n\n\ +MKDIR [диÑк:]путь\nMD [диÑк:]путь" STRING_MKLINK_HELP, "Creates a filesystem link object.\n\n\ MKLINK [/D | /H | /J] linkname target\n\n\ @@ -312,167 +312,167 @@ MKLINK [/D | /H | /J] linkname target\n\n\ /J Create a directory junction.\n\n\ If neither /H or /J is specified, a symbolic link is created." -STRING_MEMMORY_HELP1, "Âûâîä îáúåìà ñèñòåìíîé ïàìÿòè.\n\nMEMORY" +STRING_MEMMORY_HELP1, "Вывод объема ÑиÑтемной памÑти.\n\nMEMORY" STRING_MEMMORY_HELP2, "\n %12s%% memory load.\n\n\ - %13s áàéò âñåãî ôèçè÷åñêîé ïàìÿòè.\n\ - %13s áàéò äîñòóïíî ôèçè÷åñêîé ïàìÿòè.\n\n\ - %13s áàéò âñåãî â ôàéëå ïîäêà÷êè.\n\ - %13s áàéò äîñòóïíî â ôàéëå ïîäêà÷êè.\n\n\ - %13s áàéò âñåãî âèðòóàëüíîé ïàìÿòè.\n\ - %13s áàéò äîñòóïíî âèðòóàëüíî ïàìÿòè.\n" + %13s байт вÑего физичеÑкой памÑти.\n\ + %13s байт доÑтупно физичеÑкой памÑти.\n\n\ + %13s байт вÑего в файле подкачки.\n\ + %13s байт доÑтупно в файле подкачки.\n\n\ + %13s байт вÑего виртуальной памÑти.\n\ + %13s байт доÑтупно виртуально памÑти.\n" -STRING_MISC_HELP1, "Ãàæìèòå êëàâèøó äëÿ ïðîäîëæåíèÿ...\n" +STRING_MISC_HELP1, "Ðажмите клавишу Ð´Ð»Ñ Ð¿Ñ€Ð¾Ð´Ð¾Ð»Ð¶ÐµÐ½Ð¸Ñ...\n" -STRING_MOVE_HELP1, "Ãåðåïèñàòü %s (Yes/No/All)? " +STRING_MOVE_HELP1, "ПерепиÑать %s (Yes/No/All)? " -STRING_MOVE_HELP2, "Ãåðåìåùåíèå ôàéëîâ è ïåðåèìåíîâàíèå ôàéëîâ è êàòàëîãîâ.\n\n\ -Ãåðåìåùåíèå îäíîãî èëè áîëåå ôàéëîâ:\n\ -MOVE [/N][äèñê:][ïóòü]èìÿ_ôàéëà1[,...] íàçíà÷åíèå\n\n\ -Ãåðåèìåíîâàíèå êàòàëîãà:\n\ -MOVE [/N][äèñê:][ïóòü]èìÿ_êàòàëîãà1 èìÿ_êàòàëîãà2\n\n\ - [äèñê:][ïóòü]èìÿ_ôàéëà1 Óêàçûâàåò ìåñòîïîëîæåíèå è èìÿ ôàéëà èëè ôàéëîâ\n\ - êîòîðûå íåîáõîäèìî ïåðåìåñòèòü.\n\ +STRING_MOVE_HELP2, "Перемещение файлов и переименование файлов и каталогов.\n\n\ +Перемещение одного или более файлов:\n\ +MOVE [/N][диÑк:][путь]имÑ_файла1[,...] назначение\n\n\ +Переименование каталога:\n\ +MOVE [/N][диÑк:][путь]имÑ_каталога1 имÑ_каталога2\n\n\ + [диÑк:][путь]имÑ_файла1 Указывает меÑтоположение и Ð¸Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð° или файлов\n\ + которые необходимо перемеÑтить.\n\ /N Nothing. Do everything but move files or directories.\n\n\ -Òåêóùèå îãðàíè÷åíèÿ:\n\ - - Ãåâîçìîæíî ïåðåíîñèòü ôàéëû èëè ïàïêè ìåæäó ðàçíûìè ðàçäåëàìè.\n" +Текущие ограничениÑ:\n\ + - Ðевозможно переноÑить файлы или папки между разными разделами.\n" -STRING_MSGBOX_HELP, "Âûâîä îêíà ñ ñîîáùåíèåì è âîçâðàò îòâåòà ïîëüçîâàòåëÿ\n\n\ -MSGBOX òèï ['çàãîëîâîê'] ïîäñêàçêà\n\n\ -òèï âûâîäèìûå êíîïêè\n\ - âîçìîæíûå çíà÷åíèÿ: OK, OKCANCEL,\n\ +STRING_MSGBOX_HELP, "Вывод окна Ñ Ñообщением и возврат ответа пользователÑ\n\n\ +MSGBOX тип ['заголовок'] подÑказка\n\n\ +тип выводимые кнопки\n\ + возможные значениÑ: OK, OKCANCEL,\n\ YESNO, YESNOCANCEL\n\ -çàãîëîâîê çàãîëîâîê îêíà ñ ñîîáùåíèåì\n\ -ïîäñêàçêà âûâîäèìûé òåêñò ïîäñêàçêè\n\n\n\ -ERRORLEVEL óñòàíàâëèâàåòñÿ â ñîîòâåòñòâèè ñ íàæàòîé êíîïêîé:\n\n\ +заголовок заголовок окна Ñ Ñообщением\n\ +подÑказка выводимый текÑÑ‚ подÑказки\n\n\n\ +ERRORLEVEL уÑтанавливаетÑÑ Ð² ÑоответÑтвии Ñ Ð½Ð°Ð¶Ð°Ñ‚Ð¾Ð¹ кнопкой:\n\n\ YES : 10 | NO : 11\n\ OK : 10 | CANCEL : 12\n" -STRING_PATH_HELP1, "Âûâîä èëè çàäàíèå ïóòè ïîèñêà èñïîëíÿåìûõ ôàéëîâ.\n\n\ -PATH [[äèñê:]ïóòü[;...]]\nPATH ;\n\n\ -Êîìàíäà PATH ; î÷èùàåò ïóòü ïîèñêà èñïîëüçóåìûõ ôàéëîâ, îãðàíè÷èâ åãî\n\ -òåêóùèì êàòàëîãîì.\n\ -Êîìàíäà PATH áåç ïàðàìåòðîâ îòîáðàæàåò òåêóùèé ïóòü ïîèñêà.\n" +STRING_PATH_HELP1, "Вывод или задание пути поиÑка иÑполнÑемых файлов.\n\n\ +PATH [[диÑк:]путь[;...]]\nPATH ;\n\n\ +Команда PATH ; очищает путь поиÑка иÑпользуемых файлов, ограничив его\n\ +текущим каталогом.\n\ +Команда PATH без параметров отображает текущий путь поиÑка.\n" -STRING_PROMPT_HELP1, "Èçìåíåíèå ïðèãëàøåíèÿ êîìàíäíîé ñòðîêè.\n\n\ -PROMPT [òåêñò]\n\n\ - òåêñò Ãîâîå ïðèãëàøåíèå êîìàíäíîé ñòðîêè.\n\n\ -Ãðèãëàøåíèå ìîæåò âêëþ÷àòü îáû÷íûå ñèìâîëû è ñëåäóþùèå êîäû:\n\n\ - $A & (àìïåðñàíä)\n\ - $B | (âåðòèêàëüíàÿ ÷åðòà)\n\ - $C ( (ëåâàÿ êðóãëàÿ ñêîáêà)\n\ - $D Òåêóùàÿ äàòà\n\ - $E ESC (ñèìâîë ASCII ñ êîäîì 27)\n\ - $F ) (ïðàâàÿ êðóãëàÿ ñêîáêà)\n\ - $G > (çíàê ""áîëüøå"")\n\ - $H BACKSPACE (óäàëåíèå ïðåäûäóùåãî ñèìâîëà)\n\ - $L < (çíàê ""ìåíüøå"")\n\ - $N Òåêóùèé äèñê\n\ - $P Òåêóùèå äèñê è êàòàëîã\n\ - $Q = (çíàê ðàâåíñòâà)\n\ - $T Òåêóùåå âðåìÿ\n\ - $V Ãîìåð âåðñèè îïåðàöèîííîé ñèñòåìû\n\ - $_ Ãåðåâîä ñòðîêè\n\ - $$ $ (çíàê äîëëàðà)\n" +STRING_PROMPT_HELP1, "Изменение Ð¿Ñ€Ð¸Ð³Ð»Ð°ÑˆÐµÐ½Ð¸Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð½Ð¾Ð¹ Ñтроки.\n\n\ +PROMPT [текÑÑ‚]\n\n\ + текÑÑ‚ Ðовое приглашение командной Ñтроки.\n\n\ +Приглашение может включать обычные Ñимволы и Ñледующие коды:\n\n\ + $A & (амперÑанд)\n\ + $B | (Ð²ÐµÑ€Ñ‚Ð¸ÐºÐ°Ð»ÑŒÐ½Ð°Ñ Ñ‡ÐµÑ€Ñ‚Ð°)\n\ + $C ( (Ð»ÐµÐ²Ð°Ñ ÐºÑ€ÑƒÐ³Ð»Ð°Ñ Ñкобка)\n\ + $D Ð¢ÐµÐºÑƒÑ‰Ð°Ñ Ð´Ð°Ñ‚Ð°\n\ + $E ESC (Ñимвол ASCII Ñ ÐºÐ¾Ð´Ð¾Ð¼ 27)\n\ + $F ) (Ð¿Ñ€Ð°Ð²Ð°Ñ ÐºÑ€ÑƒÐ³Ð»Ð°Ñ Ñкобка)\n\ + $G > (знак ""больше"")\n\ + $H BACKSPACE (удаление предыдущего Ñимвола)\n\ + $L < (знак ""меньше"")\n\ + $N Текущий диÑк\n\ + $P Текущие диÑк и каталог\n\ + $Q = (знак равенÑтва)\n\ + $T Текущее времÑ\n\ + $V Ðомер верÑии операционной ÑиÑтемы\n\ + $_ Перевод Ñтроки\n\ + $$ $ (знак доллара)\n" -STRING_PAUSE_HELP1, "Ãðèîñòàíîâêà âûïîëíåíèÿ ïàêåòíîãî ôàéëà è âûâîä ñîîáùåíèÿ:\n\ -'Äëÿ ïðîäîëæåíèÿ íàæìèòå ëþáóþ êëàâèøó...' èëè óêàçàííîå ñîîáùåíèå.\n\n\ -PAUSE [ñîîáùåíèå]" +STRING_PAUSE_HELP1, "ПриоÑтановка Ð²Ñ‹Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ Ð¿Ð°ÐºÐµÑ‚Ð½Ð¾Ð³Ð¾ файла и вывод ÑообщениÑ:\n\ +'Ð”Ð»Ñ Ð¿Ñ€Ð¾Ð´Ð¾Ð»Ð¶ÐµÐ½Ð¸Ñ Ð½Ð°Ð¶Ð¼Ð¸Ñ‚Ðµ любую клавишу...' или указанное Ñообщение.\n\n\ +PAUSE [Ñообщение]" STRING_PROMPT_HELP2, " $+ Displays the current depth of the directory stack" -STRING_PROMPT_HELP3, "\nPROMPT áåç ïàðàìåòðîâ óñòàíàâëèâàåò ïðèãëàøåíèå êîìàíäíîé ñòðîêè ïî óìîë÷àíèþ." +STRING_PROMPT_HELP3, "\nPROMPT без параметров уÑтанавливает приглашение командной Ñтроки по умолчанию." -STRING_REM_HELP, "Ãîìåùåíèå êîììåíòàðèåâ â ïàêåòíûå ôàéëû.\n\nREM [êîììåíòàðèé]" +STRING_REM_HELP, "Помещение комментариев в пакетные файлы.\n\nREM [комментарий]" -STRING_RMDIR_HELP, "Óäàëåíèå êàòàëîãà.\n\n\ -RMDIR [äèñê:]ïóòü\nRD [äèñê:]ïóòü\n\ -/S Óäàëåíèå äåðåâà êàòàëîãîâ\n\ -/Q Îòêëþ÷åíèå çàïðîñà ïîäòâåðæäåíèÿ\n" -STRING_RMDIR_HELP2, "Êàòàëîã ïóñò!\n" +STRING_RMDIR_HELP, "Удаление каталога.\n\n\ +RMDIR [диÑк:]путь\nRD [диÑк:]путь\n\ +/S Удаление дерева каталогов\n\ +/Q Отключение запроÑа подтверждениÑ\n" +STRING_RMDIR_HELP2, "Каталог пуÑÑ‚!\n" -STRING_REN_HELP1, "Ãåðåèìåíîâàíèå îäíîãî èëè íåñêîëüêèõ ôàéëîâ èëè êàòàëîãîâ.\n\n\ -RENAME [/E /N /P /Q /S /T] ñòàðîå_èìÿ ... íîâîå_èìÿ\n\ -REN [/E /N /P /Q /S /T] ñòàðîå_èìÿ ... íîâîå_èìÿ\n\n\ - /E ÃÃ¥ âûâîäèòü ñîîáùåíèÿ îá îøèáêàõ.\n\ +STRING_REN_HELP1, "Переименование одного или неÑкольких файлов или каталогов.\n\n\ +RENAME [/E /N /P /Q /S /T] Ñтарое_Ð¸Ð¼Ñ ... новое_имÑ\n\ +REN [/E /N /P /Q /S /T] Ñтарое_Ð¸Ð¼Ñ ... новое_имÑ\n\n\ + /E Ðе выводить ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð¾Ð± ошибках.\n\ /N Nothing.\n\ - /P Çàïðîñ ïîäòâåðæäåíèÿ ïåðåä ïåðåèìåíîâàíèåì.\n\ - (ÃÃ¥ ðåàëèçîâàíî â äàííûé ìîìåíò!)\n\ + /P Ð—Ð°Ð¿Ñ€Ð¾Ñ Ð¿Ð¾Ð´Ñ‚Ð²ÐµÑ€Ð¶Ð´ÐµÐ½Ð¸Ñ Ð¿ÐµÑ€ÐµÐ´ переименованием.\n\ + (Ðе реализовано в данный момент!)\n\ /Q Quiet.\n\ - /S Ãåðåèìåíîâûâàòü ïîäêàòàëîãè.\n\ - /T Âûâîä êîëè÷åñòâà ïåðåèìåíîâàííûõ ôàéëîâ.\n\n\ -Äëÿ êîíå÷íîãî ôàéëà íåëüçÿ óêàçàòü äðóãîé äèñê èëè êàòàëîã.\n\ -Äëÿ ýòîé öåëè ñëåäóåò èñïîëüçîâàòü êîìàíäó MOVE.\n" + /S Переименовывать подкаталоги.\n\ + /T Вывод количеÑтва переименованных файлов.\n\n\ +Ð”Ð»Ñ ÐºÐ¾Ð½ÐµÑ‡Ð½Ð¾Ð³Ð¾ файла Ð½ÐµÐ»ÑŒÐ·Ñ ÑƒÐºÐ°Ð·Ð°Ñ‚ÑŒ другой диÑк или каталог.\n\ +Ð”Ð»Ñ Ñтой цели Ñледует иÑпользовать команду MOVE.\n" -STRING_REN_HELP2, " %lu ôàéë ïåðåèìåíîâàí\n" +STRING_REN_HELP2, " %lu файл переименован\n" -STRING_REN_HELP3, " %lu ôàéëîâ ïåðåèìåíîâàíî\n" +STRING_REN_HELP3, " %lu файлов переименовано\n" -STRING_SHIFT_HELP, "Èçìåíåíèå ñîäåðæèìîãî (ñäâèã) ïîäñòàâëÿåìûõ ïàðàìåòðîâ äëÿ ïàêåòíîãî ôàéëà.\n\n\ +STRING_SHIFT_HELP, "Изменение Ñодержимого (Ñдвиг) подÑтавлÑемых параметров Ð´Ð»Ñ Ð¿Ð°ÐºÐµÑ‚Ð½Ð¾Ð³Ð¾ файла.\n\n\ SHIFT [DOWN]" -STRING_SCREEN_HELP, "Ãåðåìåùåíèå êóðñîðà è âûâîä òåêñòà\n\n\ -SCREEN ñòð êîë [òåêñò]\n\n\ - ñòð ñòðîêà, íà êîòîðóþ ñëåäóåò ïåðåìåñòèòü êóðñîð\n\ - êîë êîëîíêà, íà êîòîðóþ ñëåäóåò ïåðåìåñòèòü êóðñîð" +STRING_SCREEN_HELP, "Перемещение курÑора и вывод текÑта\n\n\ +SCREEN Ñтр кол [текÑÑ‚]\n\n\ + Ñтр Ñтрока, на которую Ñледует перемеÑтить курÑор\n\ + кол колонка, на которую Ñледует перемеÑтить курÑор" -STRING_SET_HELP, "Âûâîä, çàäàíèå è óäàëåíèå ïåðåìåííûõ ñðåäû.\n\n\ -SET [ïåðåìåííàÿ[=][çíà÷åíèå]]\n\n\ - ïåðåìåííàÿ Èìÿ ïåðåìåííîé ñðåäû.\n\ - çíà÷åíèå Ñòðîêà ñèìâîëîâ, ïðèñâàèâàåìàÿ óêàçàííîé ïåðåìåííîé.\n\n\ -SET áåç ïàðàìåòðîâ âûâîäèò òåêóùèå çíà÷åíèÿ ïåðåìåííûõ ñðåäû.\n" +STRING_SET_HELP, "Вывод, задание и удаление переменных Ñреды.\n\n\ +SET [переменнаÑ[=][значение]]\n\n\ + Ð¿ÐµÑ€ÐµÐ¼ÐµÐ½Ð½Ð°Ñ Ð˜Ð¼Ñ Ð¿ÐµÑ€ÐµÐ¼ÐµÐ½Ð½Ð¾Ð¹ Ñреды.\n\ + значение Строка Ñимволов, приÑÐ²Ð°Ð¸Ð²Ð°ÐµÐ¼Ð°Ñ ÑƒÐºÐ°Ð·Ð°Ð½Ð½Ð¾Ð¹ переменной.\n\n\ +SET без параметров выводит текущие Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð¿ÐµÑ€ÐµÐ¼ÐµÐ½Ð½Ñ‹Ñ… Ñреды.\n" -STRING_START_HELP1, "Çàïóñê óêàçàííîé ïðîãðàììû èëè êîìàíäû.\n\n\ -START êîìàíäà\n\n\ - êîìàíäà Êîìàíäà èëè ïðîãðàììà äëÿ çàïóñêà.\n\n\ +STRING_START_HELP1, "ЗапуÑк указанной программы или команды.\n\n\ +START команда\n\n\ + команда Команда или программа Ð´Ð»Ñ Ð·Ð°Ð¿ÑƒÑка.\n\n\ At the moment all commands are started asynchronously.\n" -STRING_TITLE_HELP, "Èçìåíåíèå çàãîëîâêà îêíà êîìàíäíîé ñòðîêè.\n\n\ -TITLE [ñòðîêà]\n\n\ -ñòðîêà Ãóäóùèé çàãîëîâîê îêíà êîìàíäíîé ñòðîêè.\n" +STRING_TITLE_HELP, "Изменение заголовка окна командной Ñтроки.\n\n\ +TITLE [Ñтрока]\n\n\ +Ñтрока Будущий заголовок окна командной Ñтроки.\n" -STRING_TIME_HELP1, "Âûâîä èëè èçìåíåíèå âðåìåíè.\n\n\ -TIME [/T][âðåìÿ]\n\n\ - /T íå èçìåíÿòü âðåìÿ\n\n\ -TIME áåç ïàðàìåòðîâ âûâîäèò òåêóùåå âðåìÿ è çàïðàøèâàåò\n\ -íîâîå âðåìÿ. Ãàæàòèå ENTER ñîõðàíèò òåêóùåå âðåìÿ.\n" +STRING_TIME_HELP1, "Вывод или изменение времени.\n\n\ +TIME [/T][времÑ]\n\n\ + /T не изменÑть времÑ\n\n\ +TIME без параметров выводит текущее Ð²Ñ€ÐµÐ¼Ñ Ð¸ запрашивает\n\ +новое времÑ. Ðажатие ENTER Ñохранит текущее времÑ.\n" -STRING_TIME_HELP2, "Ââåäèòå íîâîå âðåìÿ: " +STRING_TIME_HELP2, "Введите новое времÑ: " -STRING_TIMER_HELP1, "Ãðîøëî %d ìñåê\n" +STRING_TIMER_HELP1, "Прошло %d мÑек\n" -STRING_TIMER_HELP2, "Ãðîøëî %02d%c%02d%c%02d%c%02d\n" +STRING_TIMER_HELP2, "Прошло %02d%c%02d%c%02d%c%02d\n" -STRING_TIMER_HELP3, "Ñåêóíäîìåð.\n\n\ +STRING_TIMER_HELP3, "Секундомер.\n\n\ TIMER [ON|OFF] [/S] [/n] [/Fn]\n\n\ - ON Âêëþ÷èòü ñåêóíäîìåð\n\ - OFF Âûêëþ÷èòü ñåêóíäîìåð\n\ - /S Ãàçíèöà âðåìåíè. Âîçâðàùàåò ðàçíèöó âðåìåíè\n\ - ñåêóíäîìåðà áåç èçìåíåíèÿ åãî çíà÷åíèÿ\n\ - /n Çàäàòü íîìåð ñåêóíäîìåðà.\n\ - Äîñòóïíûå íîìåðà - îò 0 äî 9\n\ - Çíà÷åíèå ïî óìîë÷àíèþ - 1\n\ - /Fn Ôîðìàò âûâîäà\n\ - n îäíî èç:\n\ - 0 ìèëëèñåêóíäû\n\ - 1 ÷÷%cìì%cññ%cää\n\n\ -Åñëè íè îäèí èç ïàðàìåòðîâ íå óêàçàí, êîìàíäà\n\ -ïåðåêëþ÷àåò ñîñòîÿíèå ñåêóíäîìåðà\n\n" + ON Включить Ñекундомер\n\ + OFF Выключить Ñекундомер\n\ + /S Разница времени. Возвращает разницу времени\n\ + Ñекундомера без Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ ÐµÐ³Ð¾ значениÑ\n\ + /n Задать номер Ñекундомера.\n\ + ДоÑтупные номера - от 0 до 9\n\ + Значение по умолчанию - 1\n\ + /Fn Формат вывода\n\ + n одно из:\n\ + 0 миллиÑекунды\n\ + 1 чч%cмм%cÑÑ%cдд\n\n\ +ЕÑли ни один из параметров не указан, команда\n\ +переключает ÑоÑтоÑние Ñекундомера\n\n" -STRING_TYPE_HELP1, "Âûâîä ñîäåðæèìîãî îäíîãî èëè íåñêîëüêèõ òåêñòîâûõ ôàéëîâ.\n\nTYPE [äèñê:][ïóòü]èìÿ ôàéëà \n\ - /P Ãîýêðàííûé âûâîä.\n" +STRING_TYPE_HELP1, "Вывод Ñодержимого одного или неÑкольких текÑтовых файлов.\n\nTYPE [диÑк:][путь]Ð¸Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð° \n\ + /P ПоÑкранный вывод.\n" STRING_VERIFY_HELP1, "This command is just a dummy!!\n\ -Âêëþ÷åíèå èëè îòêëþ÷åíèå ðåæèìà ïðîâåðêè ïðàâèëüíîñòè çàïèñè ôàéëîâ a\n\ -íà äèñê.\n\n\ +Включение или отключение режима проверки правильноÑти запиÑи файлов a\n\ +на диÑк.\n\n\ VERIFY [ON | OFF]\n\n\ -VERIFY áåç ïàðàìåòðà âûâîäèò òåêóùåå çíà÷åíèå ýòîé êîìàíäû.\n" +VERIFY без параметра выводит текущее значение Ñтой команды.\n" STRING_VERIFY_HELP2, "VERIFY %s.\n" -STRING_VERIFY_HELP3, "Ãåîáõîäèìî óêàçàòü ON èëè OFF." +STRING_VERIFY_HELP3, "Ðеобходимо указать ON или OFF." -STRING_VERSION_HELP1, "Âûâîä âåðñèè\n\n\ +STRING_VERSION_HELP1, "Вывод верÑии\n\n\ VER [/C][/R][/W]\n\n\ /C Displays credits.\n\ /R Displays redistribution information.\n\ @@ -493,175 +493,175 @@ STRING_VERSION_HELP4, "\n This program is free software; you can redistribute it the Free Software Foundation; either version 2 of the License, or\n\ (at your option) any later version.\n" -STRING_VERSION_HELP5, "\nÃîñûëàéòå îò÷åòû îá îøèáêàõ íà .\n\ -Îáíîâëåíèÿ äîñòóïíû ïî àäðåñó: http://www.reactos.org/" +STRING_VERSION_HELP5, "\nПоÑылайте отчеты об ошибках на .\n\ +ÐžÐ±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ð´Ð¾Ñтупны по адреÑу: http://www.reactos.org/" -STRING_VERSION_HELP6, "\nFreeDOS-âåðñèÿ íàïèñàíà:\n" +STRING_VERSION_HELP6, "\nFreeDOS-верÑÐ¸Ñ Ð½Ð°Ð¿Ð¸Ñана:\n" -STRING_VERSION_HELP7, "\nReactOS-âåðñèÿ íàïèñàíà:\n" +STRING_VERSION_HELP7, "\nReactOS-верÑÐ¸Ñ Ð½Ð°Ð¿Ð¸Ñана:\n" -STRING_VOL_HELP1, " Òîì â óñòðîéñòâå %c èìååò ìåòêó %s\n" -STRING_VOL_HELP2, " Òîì â óñòðîéñòâå %c íå èìååò ìåòêè\n" -STRING_VOL_HELP3, " Ñåðèéíûé íîìåð òîìà: %04X-%04X\n" -STRING_VOL_HELP4, "Âûâîäèò ìåòêó òîìà è ñåðèéíûé íîìåð.\n\nVOL [äèñê:]" +STRING_VOL_HELP1, " Том в уÑтройÑтве %c имеет метку %s\n" +STRING_VOL_HELP2, " Том в уÑтройÑтве %c не имеет метки\n" +STRING_VOL_HELP3, " Серийный номер тома: %04X-%04X\n" +STRING_VOL_HELP4, "Выводит метку тома и Ñерийный номер.\n\nVOL [диÑк:]" -STRING_WINDOW_HELP1, "Ìåíÿåò âèä îêíà êîíñîëè\n\n\ -WINDOW [/POS[=]left,top,øèðèíà,âûñîòà]\n\ - [MIN|MAX|RESTORE] ['çàãîëîâîê']\n\n\ -/POS óêàçûâàåò ðàçìåð è ïîëîæåíèå îêíà\n\ -MIN ñâîðà÷èâàåò îêíî\n\ -MAX ðàçâîðà÷èâàåò îêíî\n\ -RESTORE âîññòàíàâëèâàåò îêíî\n" +STRING_WINDOW_HELP1, "МенÑет вид окна конÑоли\n\n\ +WINDOW [/POS[=]left,top,ширина,выÑота]\n\ + [MIN|MAX|RESTORE] ['заголовок']\n\n\ +/POS указывает размер и положение окна\n\ +MIN Ñворачивает окно\n\ +MAX разворачивает окно\n\ +RESTORE воÑÑтанавливает окно\n" -STRING_WINDOW_HELP2, "Ìåíÿåò âèä îêíà êîíñîëè\n\n\ -ACTIVATE 'window' [/POS[=]left,top,øèðèíà,âûñîòà]\n\ - [MIN|MAX|RESTORE] ['çàãîëîâîê']\n\n\ -window çàãîëîâîê îêíà, âèä êîòîðîãî ñëåäóåò ìåíÿòü\n\ -/POS óêàçûâàåò ðàçìåð è ïîëîæåíèå îêíà\n\ -MIN ñâîðà÷èâàåò îêíî\n\ -MAX ðàçâîðà÷èâàåò îêíî\n\ -RESTORE âîññòàíàâëèâàåò îêíî\n\ -çàãîëîâîê íîâûé çàãîëîâîê\n" +STRING_WINDOW_HELP2, "МенÑет вид окна конÑоли\n\n\ +ACTIVATE 'window' [/POS[=]left,top,ширина,выÑота]\n\ + [MIN|MAX|RESTORE] ['заголовок']\n\n\ +window заголовок окна, вид которого Ñледует менÑть\n\ +/POS указывает размер и положение окна\n\ +MIN Ñворачивает окно\n\ +MAX разворачивает окно\n\ +RESTORE воÑÑтанавливает окно\n\ +заголовок новый заголовок\n" -STRING_HELP1, "Ñïèñîê âñåõ äîñòóïíûõ êîìàíä ñ êîðîòêèì îïèñàíèåì\n\n\ - êîìàíäà /? Âûâîäèò ïîäðîáíóþ èíôîðìàöèþ î êîìàíäå\n\n\ -? Ñïèñîê âñåõ äîñòóïíûõ êîìàíä áåç îïèñàíèÿ.\n\ -ALIAS Âûâîä, óñòàíîâêà èëè óäàëåíèå ïñåâäîíèìîâ.\n\ -ATTRIB Âûâîä è èçìåíåíèå àòðèáóòîâ ôàéëîâ.\n\ -BEEP Çâóêîâîé ñèãíàë.\n\ -CALL Âûçîâ îäíîãî ïàêåòíîãî ôàéëà èç äðóãîãî.\n\ -CD Âûâîä èìåíè ëèáî ñìåíà òåêóùåãî êàòàëîãà.\n\ -CHCP Âûâîä èëè ñìåíà òåêóùåãî íîìåðà êîäîâîé ñòðàíèöû.\n\ -CHOICE Æäåò, ïîêà ïîëüçîâàòåëü íå âûáåðåò îäèí èç óêàçàííûõ â ñïèñêå ñèìâîëîâ.\n\ -CLS Î÷èñòêà ýêðàíà.\n\ -CMD Çàïóñê íîâîé êîïèè èíòåðïðåòàòîðà êîìàíä.\n\ -COLOR Óñòàíîâêà öâåòîâ ïî óìîë÷àíèþ äëÿ òåêñòà è ôîíà.\n\ -COPY Êîïèðîâàíèå îäíîãî èëè íåñêîëüêèõ ôàéëîâ â äðóãîå ìåñòî.\n\ -DATE Âûâîä èëè èçìåíåíèå äàòû.\n\ -DELETE Óäàëåíèå îäíîãî èëè íåñêîëüêèõ ôàéëîâ.\n\ -DIR Âûâîä ñïèñêà ôàéëîâ è ïîäêàòàëîãîâ êàòàëîãà.\n\ -ECHO Âûâîä ñîîáùåíèé è ïåðåêëþ÷åíèå ðåæèìà îòîáðàæåíèÿ êîìàíä íà ýêðàíå.\n\ -ERASE Óäàëåíèå îäíîãî èëè íåñêîëüêèõ ôàéëîâ.\n\ -EXIT Çàâåðøàåò èíòåðïðåòàòîð êîìàíä.\n\ -FOR Çàïóñêàåò óêàçàííóþ êîìàíäó äëÿ êàæäîãî ôàéëà èç íàáîðà ôàéëîâ.\n\ -FREE (Ñâîáîäíîå) äèñêîâîå ïðîñòðàíñòâî.\n\ -GOTO Ãåðåäà÷à óïðàâëåíèÿ ñîäåðæàùåé ìåòêó ñòðîêå ïàêåòíîãî ôàéëà\n\ -HELP Ãðåäîñòàâëÿåò ñïðàâî÷íóþ èíôîðìàöèþ î êîìàíäàõ ReactOS.\n\ -HISTORY Ñïèñîê çàïóùåííûõ êîìàíä\n\ -IF Îïåðàòîð óñëîâíîãî âûïîëíåíèÿ êîìàíä â ïàêåòíîì ôàéëå.\n\ -LABEL Ñîçäàíèå, èçìåíåíèå è óäàëåíèå ìåòîê òîìà.\n\ -MD Ñîçäàíèå êàòàëîãà.\n\ -MKDIR Ñîçäàíèå êàòàëîãà.\n\ +STRING_HELP1, "СпиÑок вÑех доÑтупных команд Ñ ÐºÐ¾Ñ€Ð¾Ñ‚ÐºÐ¸Ð¼ опиÑанием\n\n\ + команда /? Выводит подробную информацию о команде\n\n\ +? СпиÑок вÑех доÑтупных команд без опиÑаниÑ.\n\ +ALIAS Вывод, уÑтановка или удаление пÑевдонимов.\n\ +ATTRIB Вывод и изменение атрибутов файлов.\n\ +BEEP Звуковой Ñигнал.\n\ +CALL Вызов одного пакетного файла из другого.\n\ +CD Вывод имени либо Ñмена текущего каталога.\n\ +CHCP Вывод или Ñмена текущего номера кодовой Ñтраницы.\n\ +CHOICE Ждет, пока пользователь не выберет один из указанных в ÑпиÑке Ñимволов.\n\ +CLS ОчиÑтка Ñкрана.\n\ +CMD ЗапуÑк новой копии интерпретатора команд.\n\ +COLOR УÑтановка цветов по умолчанию Ð´Ð»Ñ Ñ‚ÐµÐºÑта и фона.\n\ +COPY Копирование одного или неÑкольких файлов в другое меÑто.\n\ +DATE Вывод или изменение даты.\n\ +DELETE Удаление одного или неÑкольких файлов.\n\ +DIR Вывод ÑпиÑка файлов и подкаталогов каталога.\n\ +ECHO Вывод Ñообщений и переключение режима Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´ на Ñкране.\n\ +ERASE Удаление одного или неÑкольких файлов.\n\ +EXIT Завершает интерпретатор команд.\n\ +FOR ЗапуÑкает указанную команду Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð³Ð¾ файла из набора файлов.\n\ +FREE (Свободное) диÑковое проÑтранÑтво.\n\ +GOTO Передача ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ñодержащей метку Ñтроке пакетного файла\n\ +HELP ПредоÑтавлÑет Ñправочную информацию о командах ReactOS.\n\ +HISTORY СпиÑок запущенных команд\n\ +IF Оператор уÑловного Ð²Ñ‹Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´ в пакетном файле.\n\ +LABEL Создание, изменение и удаление меток тома.\n\ +MD Создание каталога.\n\ +MKDIR Создание каталога.\n\ MKLINK Creates a filesystem link object.\n\ -MOVE Ãåðåìåùåíèå ôàéëîâ è ïåðåèìåíîâàíèå ôàéëîâ è êàòàëîãîâ\n\ -PATH Âûâîä èëè çàäàíèå ïóòè ïîèñêà èñïîëíÿåìûõ ôàéëîâ.\n\ -PAUSE Ãðèîñòàíîâêà âûïîëíåíèÿ ïàêåòíîãî ôàéëà.\n\ -POPD Âîñòòàíàâëèâàåò ïðåäûäóùåå çíà÷åíèå òåêóùåé äèðåêòîðèè ñîõðàíåííîå êîìàíäîé\n\ +MOVE Перемещение файлов и переименование файлов и каталогов\n\ +PATH Вывод или задание пути поиÑка иÑполнÑемых файлов.\n\ +PAUSE ПриоÑтановка Ð²Ñ‹Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ Ð¿Ð°ÐºÐµÑ‚Ð½Ð¾Ð³Ð¾ файла.\n\ +POPD ВоÑттанавливает предыдущее значение текущей директории Ñохраненное командой\n\ PUSHD.\n\ -PROMPT Èçìåíåíèå ïðèãëàøåíèÿ êîìàíäíîé ñòðîêè.\n\ -PUSHD Ñîõðàíÿåò òåêóùóþ äèðåêòîðèþ, à ïîòîì ìåíÿåò åå.\n\ -RD Óäàëåíèå êàòàëîãà.\n\ -REM Çàïèñûâàåò êîììåíòàðèè (çàìå÷åíèÿ) â ïàêåòíûõ ôàéëàõ.\n\ -REN Ãåðåèìåíîâàíèå îäíîãî èëè íåñêîëüêèõ ôàéëîâ èëè êàòàëîãîâ.\n\ -RENAME Ãåðåèìåíîâàíèå îäíîãî èëè íåñêîëüêèõ ôàéëîâ èëè êàòàëîãîâ.\n\ -RMDIR Óäàëåíèå êàòàëîãà.\n\ -SCREEN Ãåðåìåùåíèå êóðñîðà è âûâîä òåêñòà.\n\ -SET Âûâîä, çàäàíèå è óäàëåíèå ïåðåìåííûõ ñðåäû.\n\ -SHIFT Èçìåíåíèå ñîäåðæèìîãî (ñäâèã) ïîäñòàâëÿåìûõ ïàðàìåòðîâ äëÿ ïàêåòíîãî ôàéëà\n" -STRING_HELP2, "START Îòêðûâàåò îòäåëüíîå îêíî äëÿ çàïóñêà óêàçàííûõ êîìàíä èëè ïðîãðàìì.\n\ - Âûïîëíÿåò êîìàíäó.\n\ -TIME Âûâîä èëè èçìåíåíèå âðåìåíè.\n\ -TIMER Ñåêóíäîìåð.\n\ -TITLE Èçìåíåíèå çàãîëîâêà îêíà êîìàíäíîé ñòðîêè.\n\ -TYPE Âûâîä ñîäåðæèìîãî îäíîãî èëè íåñêîëüêèõ òåêñòîâûõ ôàéëîâ.\n\ -VER Âûâîä âåðñèè ÎÑ.\n\ -VERIFY Âêëþ÷åíèå èëè îòêëþ÷åíèå ðåæèìà ïðîâåðêè ïðàâèëüíîñòè çàïèñè ôàéëîâ\n\ - íà äèñê.\n\ -VOL Âûâîäèò ìåòêó òîìà è ñåðèéíûé íîìåð.\n" +PROMPT Изменение Ð¿Ñ€Ð¸Ð³Ð»Ð°ÑˆÐµÐ½Ð¸Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð½Ð¾Ð¹ Ñтроки.\n\ +PUSHD СохранÑет текущую директорию, а потом менÑет ее.\n\ +RD Удаление каталога.\n\ +REM ЗапиÑывает комментарии (замечениÑ) в пакетных файлах.\n\ +REN Переименование одного или неÑкольких файлов или каталогов.\n\ +RENAME Переименование одного или неÑкольких файлов или каталогов.\n\ +RMDIR Удаление каталога.\n\ +SCREEN Перемещение курÑора и вывод текÑта.\n\ +SET Вывод, задание и удаление переменных Ñреды.\n\ +SHIFT Изменение Ñодержимого (Ñдвиг) подÑтавлÑемых параметров Ð´Ð»Ñ Ð¿Ð°ÐºÐµÑ‚Ð½Ð¾Ð³Ð¾ файла\n" +STRING_HELP2, "START Открывает отдельное окно Ð´Ð»Ñ Ð·Ð°Ð¿ÑƒÑка указанных команд или программ.\n\ + ВыполнÑет команду.\n\ +TIME Вывод или изменение времени.\n\ +TIMER Секундомер.\n\ +TITLE Изменение заголовка окна командной Ñтроки.\n\ +TYPE Вывод Ñодержимого одного или неÑкольких текÑтовых файлов.\n\ +VER Вывод верÑии ОС.\n\ +VERIFY Включение или отключение режима проверки правильноÑти запиÑи файлов\n\ + на диÑк.\n\ +VOL Выводит метку тома и Ñерийный номер.\n" STRING_CHOICE_OPTION, "YN" STRING_COPY_OPTION, "YNA" -STRING_ALIAS_ERROR, "Êîìàíäíàÿ ñòðîêà ñëèøêîì äëèííàÿ ïîñëå ðàçâåðòûâàíèÿ ïñåâäîíèìîâ!\n" +STRING_ALIAS_ERROR, "ÐšÐ¾Ð¼Ð°Ð½Ð´Ð½Ð°Ñ Ñтрока Ñлишком Ð´Ð»Ð¸Ð½Ð½Ð°Ñ Ð¿Ð¾Ñле Ñ€Ð°Ð·Ð²ÐµÑ€Ñ‚Ñ‹Ð²Ð°Ð½Ð¸Ñ Ð¿Ñевдонимов!\n" STRING_ASSOC_ERROR, "File association not found for extension %s\n" -STRING_BATCH_ERROR, "Îøèáêà îòêðûòèÿ êîìàíäíîãî ôàéëà\n" -STRING_CHCP_ERROR1, "Òåêóùàÿ êîäîâàÿ ñòðàíèöà: %u\n" -STRING_CHCP_ERROR4, "Îøèáî÷íàÿ êîäîâàÿ ñòðàíèöà\n" -STRING_CHOICE_ERROR, "Îøèáî÷íûé ïàðàìåòð. Îæèäàåòñÿ ôîðìàò: /C[:]ïàðàìåòðû" -STRING_CHOICE_ERROR_TXT, "Îøèáî÷íûé ïàðàìåòð. Îæèäàåòñÿ ôîðìàò: /T[:]c,nn" -STRING_CHOICE_ERROR_OPTION, "Îøèáî÷íûé ïàðàìåòð: %s" -STRING_MD_ERROR, "Ãîäêàòàëîã èëè ôàéë óæå ñóùåñòâóåò.\n" -STRING_MD_ERROR2, "Ãóòü ê íîâîìó êàòàëîãó íå ñóùåñòâóåò.\n" -STRING_CMD_ERROR1, "ÃÃ¥ ìîãó ïåðåíàïðàâèòü ââîä èç ôàéëà %s\n" -STRING_CMD_ERROR2, "Îøèáêà ñîçäàíèÿ âðåìåííîãî ôàéëà äëÿ pipe-äàííûõ\n" -STRING_CMD_ERROR3, "ÃÃ¥ ìîãó ïåðåíàïðàâèòü â ôàéë %s\n" -STRING_CMD_ERROR4, "Çàïóñê %s...\n" -STRING_CMD_ERROR5, "Çàïóñê cmdexit.bat...\n" -STRING_COLOR_ERROR1, "Îäèíàêîâûå öâåòà! (Öâåòà ôîíà è òåêñòà íå ìîãóò áûòü îäèíàêîâûìè)" -STRING_COLOR_ERROR2, "îøèáêà â óêàçàíèè öâåòà" -STRING_COLOR_ERROR3, "Öâåò %x\n" -STRING_COLOR_ERROR4, "Îäèíàêîâûå öâåòà!" -STRING_CONSOLE_ERROR, "Ãåèçâåñòíàÿ îøèáêà: %d\n" -STRING_COPY_ERROR1, "Îøèáêà: Ãåâîçìîæíî îòêðûòü èñòî÷íèê - %s!\n" -STRING_COPY_ERROR2, "Îøèáêà: Ãåâîçìîæíî êîïèðîâàòü â ñåáÿ!\n" -STRING_COPY_ERROR3, "Îøèáêà çàïèñè!\n" -STRING_COPY_ERROR4, "Îøèáêà:  äàííûé ìîìåíò íå ðåàëèçîâàíî!\n" -STRING_DATE_ERROR, "Ãåïðàâèëüíàÿ äàòà." -STRING_DEL_ERROR5, "Ôàéë %s áóäåò óäàëåí! " -STRING_DEL_ERROR6, "Âû óâåðåíû (Y/N)?" -STRING_DEL_ERROR7, "Óäàëåíèå: %s\n" -STRING_ERROR_ERROR1, "Ãåèçâåñòíàÿ îøèáêà! Êîä îøèáêè: 0x%lx\n" -STRING_ERROR_ERROR2, "Ñèíòàêñè÷åñêàÿ îøèáêà" -STRING_FOR_ERROR1, "'in' îòñóòñòâóåò â êîìàíäå for." -STRING_FOR_ERROR2, "ñêîáîê íåîáíàðóæåíî." -STRING_FOR_ERROR3, "'do' îòñóòñâóåò." -STRING_FOR_ERROR4, "íåò êîìàíäû ïîñëå 'do'." -STRING_FREE_ERROR1, "Ãåïðàâèëüíîå èìÿ äèñêà" -STRING_FREE_ERROR2, "íåîòìå÷åíî" -STRING_GOTO_ERROR1, "ÃÃ¥ îïðåäåëåíà ìåòêà äëÿ GOTO" -STRING_GOTO_ERROR2, "Ìåòêà '%s' íå íàéäåíà\n" +STRING_BATCH_ERROR, "Ошибка Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ð¸Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð½Ð¾Ð³Ð¾ файла\n" +STRING_CHCP_ERROR1, "Ð¢ÐµÐºÑƒÑ‰Ð°Ñ ÐºÐ¾Ð´Ð¾Ð²Ð°Ñ Ñтраница: %u\n" +STRING_CHCP_ERROR4, "ÐžÑˆÐ¸Ð±Ð¾Ñ‡Ð½Ð°Ñ ÐºÐ¾Ð´Ð¾Ð²Ð°Ñ Ñтраница\n" +STRING_CHOICE_ERROR, "Ошибочный параметр. ОжидаетÑÑ Ñ„Ð¾Ñ€Ð¼Ð°Ñ‚: /C[:]параметры" +STRING_CHOICE_ERROR_TXT, "Ошибочный параметр. ОжидаетÑÑ Ñ„Ð¾Ñ€Ð¼Ð°Ñ‚: /T[:]c,nn" +STRING_CHOICE_ERROR_OPTION, "Ошибочный параметр: %s" +STRING_MD_ERROR, "Подкаталог или файл уже ÑущеÑтвует.\n" +STRING_MD_ERROR2, "Путь к новому каталогу не ÑущеÑтвует.\n" +STRING_CMD_ERROR1, "Ðе могу перенаправить ввод из файла %s\n" +STRING_CMD_ERROR2, "Ошибка ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ð²Ñ€ÐµÐ¼ÐµÐ½Ð½Ð¾Ð³Ð¾ файла Ð´Ð»Ñ pipe-данных\n" +STRING_CMD_ERROR3, "Ðе могу перенаправить в файл %s\n" +STRING_CMD_ERROR4, "ЗапуÑк %s...\n" +STRING_CMD_ERROR5, "ЗапуÑк cmdexit.bat...\n" +STRING_COLOR_ERROR1, "Одинаковые цвета! (Цвета фона и текÑта не могут быть одинаковыми)" +STRING_COLOR_ERROR2, "ошибка в указании цвета" +STRING_COLOR_ERROR3, "Цвет %x\n" +STRING_COLOR_ERROR4, "Одинаковые цвета!" +STRING_CONSOLE_ERROR, "ÐеизвеÑÑ‚Ð½Ð°Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ°: %d\n" +STRING_COPY_ERROR1, "Ошибка: Ðевозможно открыть иÑточник - %s!\n" +STRING_COPY_ERROR2, "Ошибка: Ðевозможно копировать в ÑебÑ!\n" +STRING_COPY_ERROR3, "Ошибка запиÑи!\n" +STRING_COPY_ERROR4, "Ошибка: Ð’ данный момент не реализовано!\n" +STRING_DATE_ERROR, "ÐÐµÐ¿Ñ€Ð°Ð²Ð¸Ð»ÑŒÐ½Ð°Ñ Ð´Ð°Ñ‚Ð°." +STRING_DEL_ERROR5, "Файл %s будет удален! " +STRING_DEL_ERROR6, "Ð’Ñ‹ уверены (Y/N)?" +STRING_DEL_ERROR7, "Удаление: %s\n" +STRING_ERROR_ERROR1, "ÐеизвеÑÑ‚Ð½Ð°Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ°! Код ошибки: 0x%lx\n" +STRING_ERROR_ERROR2, "СинтакÑичеÑÐºÐ°Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ°" +STRING_FOR_ERROR1, "'in' отÑутÑтвует в команде for." +STRING_FOR_ERROR2, "Ñкобок необнаружено." +STRING_FOR_ERROR3, "'do' отÑутÑвует." +STRING_FOR_ERROR4, "нет команды поÑле 'do'." +STRING_FREE_ERROR1, "Ðеправильное Ð¸Ð¼Ñ Ð´Ð¸Ñка" +STRING_FREE_ERROR2, "неотмечено" +STRING_GOTO_ERROR1, "Ðе определена метка Ð´Ð»Ñ GOTO" +STRING_GOTO_ERROR2, "Метка '%s' не найдена\n" STRING_MOVE_ERROR1, "[OK]\n" -STRING_MOVE_ERROR2, "[Îøèáêà]\n" +STRING_MOVE_ERROR2, "[Ошибка]\n" -STRING_REN_ERROR1, "Âûïîëíåíèå MoveFile() áûëî íåóñïåøíûì. Îøèáêà: %lu\n" +STRING_REN_ERROR1, "Выполнение MoveFile() было неуÑпешным. Ошибка: %lu\n" -STRING_START_ERROR1, "Ãà äàííûé ìîìåíò íåò ïîääåðæêè ïàêåòíûõ ôàéëîâ!" +STRING_START_ERROR1, "Ðа данный момент нет поддержки пакетных файлов!" -STRING_TIME_ERROR1, "Ãåïðàâèëüíîå âðåìÿ." +STRING_TIME_ERROR1, "Ðеправильное времÑ." -STRING_TYPE_ERROR1, "Ãåïðàâèëüíûé ïàðàìåòð '/%s'\n" +STRING_TYPE_ERROR1, "Ðеправильный параметр '/%s'\n" -STRING_WINDOW_ERROR1, "îêíî íå íàéäåíî" +STRING_WINDOW_ERROR1, "окно не найдено" -STRING_ERROR_PARAMETERF_ERROR, "Ãåêîððåêòíûé ôîðìàò ïàðàìåòðà - %c\n" -STRING_ERROR_INVALID_SWITCH, "Ãåâåðíûé ïàðàìåòð - /%c\n" -STRING_ERROR_TOO_MANY_PARAMETERS, "Ñëèøêîì ìíîãî ïàðàìåòðîâ - %s\n" -STRING_ERROR_PATH_NOT_FOUND, "Ãóòü íå íàéäåí\n" -STRING_ERROR_FILE_NOT_FOUND, "Ôàéë íå íàéäåí\n" -STRING_ERROR_REQ_PARAM_MISSING, "Îòñóòñòâóåò íåîáõîäèìûé ïàðàìåòð\n" -STRING_ERROR_INVALID_DRIVE, "Îøèáî÷íîå îïðåäåëåíèå äèñêà\n" -STRING_ERROR_INVALID_PARAM_FORMAT, "Îøèáî÷íûé ôîðìàò ïàðàìåòðà - %s\n" -STRING_ERROR_BADCOMMAND, "Ãåïðàâèëüíàÿ êîìàíäà èëè íåâåðíîå èìÿ ôàéëà - %s\n" -STRING_ERROR_OUT_OF_MEMORY, "Ãåõâàòêà ïàìÿòè.\n" -STRING_ERROR_CANNOTPIPE, "Îøèáêà! Ãåâîçìîæíî èñïîëüçîâàòü pipe! Ãåâîçìîæíî ñîçäàòü âðåìåííûé ôàéë!\n" -STRING_ERROR_D_PAUSEMSG, "Äëÿ ïðîäîëæåíèÿ íàæìèòå ëþáóþ êëàâèøó . . ." -STRING_ERROR_DRIVER_NOT_READY, "Óñòðîéñòâî íå ãîòîâî" +STRING_ERROR_PARAMETERF_ERROR, "Ðекорректный формат параметра - %c\n" +STRING_ERROR_INVALID_SWITCH, "Ðеверный параметр - /%c\n" +STRING_ERROR_TOO_MANY_PARAMETERS, "Слишком много параметров - %s\n" +STRING_ERROR_PATH_NOT_FOUND, "Путь не найден\n" +STRING_ERROR_FILE_NOT_FOUND, "Файл не найден\n" +STRING_ERROR_REQ_PARAM_MISSING, "ОтÑутÑтвует необходимый параметр\n" +STRING_ERROR_INVALID_DRIVE, "Ошибочное определение диÑка\n" +STRING_ERROR_INVALID_PARAM_FORMAT, "Ошибочный формат параметра - %s\n" +STRING_ERROR_BADCOMMAND, "ÐÐµÐ¿Ñ€Ð°Ð²Ð¸Ð»ÑŒÐ½Ð°Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð° или неверное Ð¸Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð° - %s\n" +STRING_ERROR_OUT_OF_MEMORY, "Ðехватка памÑти.\n" +STRING_ERROR_CANNOTPIPE, "Ошибка! Ðевозможно иÑпользовать pipe! Ðевозможно Ñоздать временный файл!\n" +STRING_ERROR_D_PAUSEMSG, "Ð”Ð»Ñ Ð¿Ñ€Ð¾Ð´Ð¾Ð»Ð¶ÐµÐ½Ð¸Ñ Ð½Ð°Ð¶Ð¼Ð¸Ñ‚Ðµ любую клавишу . . ." +STRING_ERROR_DRIVER_NOT_READY, "УÑтройÑтво не готово" -STRING_PATH_ERROR, "CMD: ÃÃ¥ â ñðåäå îêðóæåíèÿ '%s'\n" +STRING_PATH_ERROR, "CMD: Ðе в Ñреде Ð¾ÐºÑ€ÑƒÐ¶ÐµÐ½Ð¸Ñ '%s'\n" STRING_REACTOS_VERSION, "ReactOS Operating System [Version %s-%s]\n" -STRING_CMD_SHELLINFO, "\nÈíòåðïðåòàòîð êîìàíäíîé ñòðîêè ReactOS\nVersion %s %s" -STRING_VERSION_RUNVER, " çàïóùåí íà %s" -STRING_COPY_FILE , " %d ôàéë(îâ) ñêîïèðîâàíî\n" +STRING_CMD_SHELLINFO, "\nИнтерпретатор командной Ñтроки ReactOS\nVersion %s %s" +STRING_VERSION_RUNVER, " запущен на %s" +STRING_COPY_FILE , " %d файл(ов) Ñкопировано\n" STRING_DELETE_WIPE, "wiped" -STRING_FOR_ERROR, "íåïðàâèëüíîå çàäàíèå ïåðåìåííîé." -STRING_SCREEN_COL, "íåïðàâèëüíîå çíà÷åíèå äëÿ êîë" -STRING_SCREEN_ROW, "íåïðàâèëüíîå çíà÷åíèå äëÿ ñòð" +STRING_FOR_ERROR, "неправильное задание переменной." +STRING_SCREEN_COL, "неправильное значение Ð´Ð»Ñ ÐºÐ¾Ð»" +STRING_SCREEN_ROW, "неправильное значение Ð´Ð»Ñ Ñтр" STRING_TIMER_TIME "Timer %d is %s: " STRING_MKLINK_CREATED_SYMBOLIC, "Symbolic link created for %s <<===>> %s\n" STRING_MKLINK_CREATED_HARD, "Hard link created for %s <<===>> %s\n" @@ -669,9 +669,9 @@ STRING_MKLINK_CREATED_JUNCTION, "Junction created for %s <<===>> %s\n" STRING_MORE, "More? " STRING_CANCEL_BATCH_FILE, "\r\nCtrl-Break pressed. Cancel batch file? (Yes/No/All) " -STRING_INVALID_OPERAND, "Ãåâåðíûé îïåðàíä." -STRING_EXPECTED_CLOSE_PAREN, "Îæèäàåòñÿ ')'." -STRING_EXPECTED_NUMBER_OR_VARIABLE,"Îæèäàåòñÿ ÷èñëî èëè íàçâàíèå ïåðåìåííîé." -STRING_SYNTAX_COMMAND_INCORRECT, "Ãåâåðíûé ñèíòàêñèñ êîìàíäû." +STRING_INVALID_OPERAND, "Ðеверный операнд." +STRING_EXPECTED_CLOSE_PAREN, "ОжидаетÑÑ ')'." +STRING_EXPECTED_NUMBER_OR_VARIABLE,"ОжидаетÑÑ Ñ‡Ð¸Ñло или название переменной." +STRING_SYNTAX_COMMAND_INCORRECT, "Ðеверный ÑинтакÑÐ¸Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ‹." END diff --git a/base/shell/explorer/explorer-pl.rc b/base/shell/explorer/explorer-pl.rc index 06a142d5ae3..9dad38a8f7a 100644 --- a/base/shell/explorer/explorer-pl.rc +++ b/base/shell/explorer/explorer-pl.rc @@ -381,8 +381,8 @@ BEGIN IDS_DESKTOPBAR_SETTINGS "W³aœciwoœci pulpitu" IDS_DESKTOP "Pulpit" IDS_TASKBAR "Pasek zadañ" - IDS_NAMECOLUMN "Name" - IDS_PATHCOLUMN "Path" + IDS_NAMECOLUMN "Nazwa" + IDS_PATHCOLUMN "Œcie¿ka" IDS_MENUCOLUMN "Menu path" END diff --git a/base/system/services/config.c b/base/system/services/config.c index b056af5c86c..bcde1d47198 100644 --- a/base/system/services/config.c +++ b/base/system/services/config.c @@ -125,7 +125,7 @@ ScmWriteDependencies(HKEY hServiceKey, lpDst = lpGroupDeps; while (*lpSrc != 0) { - dwLength = wcslen(lpSrc); + dwLength = wcslen(lpSrc) + 1; if (*lpSrc == SC_GROUP_IDENTIFIERW) { lpSrc++; @@ -157,21 +157,37 @@ ScmWriteDependencies(HKEY hServiceKey, *lpDst = 0; dwServiceLength++; - dwError = RegSetValueExW(hServiceKey, - L"DependOnGroup", - 0, - REG_MULTI_SZ, - (LPBYTE)lpGroupDeps, - dwGroupLength * sizeof(WCHAR)); + if (dwGroupLength > 1) + { + dwError = RegSetValueExW(hServiceKey, + L"DependOnGroup", + 0, + REG_MULTI_SZ, + (LPBYTE)lpGroupDeps, + dwGroupLength * sizeof(WCHAR)); + } + else + { + RegDeleteValueW(hServiceKey, + L"DependOnGroup"); + } if (dwError == ERROR_SUCCESS) { - dwError = RegSetValueExW(hServiceKey, - L"DependOnService", - 0, - REG_MULTI_SZ, - (LPBYTE)lpServiceDeps, - dwServiceLength * sizeof(WCHAR)); + if (dwServiceLength > 1) + { + dwError = RegSetValueExW(hServiceKey, + L"DependOnService", + 0, + REG_MULTI_SZ, + (LPBYTE)lpServiceDeps, + dwServiceLength * sizeof(WCHAR)); + } + else + { + RegDeleteValueW(hServiceKey, + L"DependOnService"); + } } HeapFree(GetProcessHeap(), 0, lpGroupDeps); diff --git a/dll/cpl/desk/lang/pl-PL.rc b/dll/cpl/desk/lang/pl-PL.rc index 80c38df7b7d..50f6ef58b4c 100644 --- a/dll/cpl/desk/lang/pl-PL.rc +++ b/dll/cpl/desk/lang/pl-PL.rc @@ -7,6 +7,7 @@ * Use ReactOS forum PM or IRC to contact me * http://www.reactos.org * IRC: irc.freenode.net #reactos-pl; +* update by Saibamen saibamenppl@gmail.com (29.03.2011) */ LANGUAGE LANG_POLISH, SUBLANG_DEFAULT @@ -217,11 +218,11 @@ END STRINGTABLE DISCARDABLE BEGIN - IDS_COLOR_4BIT "16 kolorów (4 Bity)" - IDS_COLOR_8BIT "256 kolorów (8 Bitów)" - IDS_COLOR_16BIT "65,536 kolorów (16 Bitów)" - IDS_COLOR_24BIT "16,777,216 kolorów (24 Bitów)" - IDS_COLOR_32BIT "16,777,216 kolorów (32 Bity)" + IDS_COLOR_4BIT "16 kolorów" + IDS_COLOR_8BIT "256 kolorów" + IDS_COLOR_16BIT "High Color (16 Bitów)" + IDS_COLOR_24BIT "True Color (24 Bitów)" + IDS_COLOR_32BIT "True Color (32 Bity)" IDS_PIXEL "%lux%lu pikseli" END diff --git a/dll/cpl/usrmgr/groupprops.c b/dll/cpl/usrmgr/groupprops.c index ac30a280c00..d34acd3eb51 100644 --- a/dll/cpl/usrmgr/groupprops.c +++ b/dll/cpl/usrmgr/groupprops.c @@ -139,7 +139,7 @@ InitGroupMembersList(HWND hwndDlg, pUserBuffer[i].usri20_comment); } - NetApiBufferFree(&pUserBuffer); + NetApiBufferFree(pUserBuffer); /* No more data left */ if (netStatus != ERROR_MORE_DATA) diff --git a/dll/cpl/usrmgr/groups.c b/dll/cpl/usrmgr/groups.c index 4eebfa40f26..445d90ad342 100644 --- a/dll/cpl/usrmgr/groups.c +++ b/dll/cpl/usrmgr/groups.c @@ -77,7 +77,7 @@ UpdateGroupsList(HWND hwndListView) pBuffer[i].lgrpi1_comment); } - NetApiBufferFree(&pBuffer); + NetApiBufferFree(pBuffer); /* No more data left */ if (netStatus != ERROR_MORE_DATA) diff --git a/dll/cpl/usrmgr/userprops.c b/dll/cpl/usrmgr/userprops.c index c007b1846d1..a9cd031f02a 100644 --- a/dll/cpl/usrmgr/userprops.c +++ b/dll/cpl/usrmgr/userprops.c @@ -432,7 +432,7 @@ InitUserGroupsList(HWND hwndDlg) pBuffer[i].lgrpi1_comment); } - NetApiBufferFree(&pBuffer); + NetApiBufferFree(pBuffer); /* No more data left */ if (netStatus != ERROR_MORE_DATA) diff --git a/dll/cpl/usrmgr/users.c b/dll/cpl/usrmgr/users.c index 04ff45eaca3..174ec2f4f57 100644 --- a/dll/cpl/usrmgr/users.c +++ b/dll/cpl/usrmgr/users.c @@ -441,7 +441,7 @@ UpdateUsersList(HWND hwndListView) pBuffer[i].usri20_comment); } - NetApiBufferFree(&pBuffer); + NetApiBufferFree(pBuffer); /* No more data left */ if (netStatus != ERROR_MORE_DATA) diff --git a/dll/ntdll/def/ntdll.spec b/dll/ntdll/def/ntdll.spec index 6e88f53caf6..879bd53fdaa 100644 --- a/dll/ntdll/def/ntdll.spec +++ b/dll/ntdll/def/ntdll.spec @@ -75,7 +75,7 @@ ;@ stdcall LdrDestroyOutOfProcessImage @ stdcall LdrDisableThreadCalloutsForDll(long) @ stdcall LdrEnumResources(ptr ptr long ptr ptr) -;@ stdcall LdrEnumerateLoadedModules +@ stdcall LdrEnumerateLoadedModules(long ptr long) ;@ stdcall LdrFindCreateProcessManifest ; 5.1 and 5.2 only @ stdcall LdrFindEntryForAddress(ptr ptr) @ stdcall LdrFindResourceDirectory_U(long ptr long ptr) diff --git a/dll/ntdll/ldr/ldrapi.c b/dll/ntdll/ldr/ldrapi.c index 0a19351dab8..e08f4ca5ec8 100644 --- a/dll/ntdll/ldr/ldrapi.c +++ b/dll/ntdll/ldr/ldrapi.c @@ -15,9 +15,6 @@ /* GLOBALS *******************************************************************/ -#define LDR_LOCK_HELD 0x2 -#define LDR_LOCK_FREE 0x1 - LONG LdrpLoaderLockAcquisitonCount; /* FUNCTIONS *****************************************************************/ @@ -38,7 +35,7 @@ LdrUnlockLoaderLock(IN ULONG Flags, if (Flags & ~1) { /* Flags are invalid, check how to fail */ - if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_STATUS) + if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS) { /* The caller wants us to raise status */ RtlRaiseStatus(STATUS_INVALID_PARAMETER_1); @@ -60,7 +57,7 @@ LdrUnlockLoaderLock(IN ULONG Flags, DPRINT1("LdrUnlockLoaderLock() called with an invalid cookie!\n"); /* Invalid cookie, check how to fail */ - if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_STATUS) + if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS) { /* The caller wants us to raise status */ RtlRaiseStatus(STATUS_INVALID_PARAMETER_2); @@ -73,7 +70,7 @@ LdrUnlockLoaderLock(IN ULONG Flags, } /* Ready to release the lock */ - if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_STATUS) + if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS) { /* Do a direct leave */ RtlLeaveCriticalSection(&LdrpLoaderLock); @@ -118,11 +115,11 @@ LdrLockLoaderLock(IN ULONG Flags, if (Cookie) *Cookie = 0; /* Validate the flags */ - if (Flags & ~(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_STATUS | + if (Flags & ~(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS | LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY)) { /* Flags are invalid, check how to fail */ - if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_STATUS) + if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS) { /* The caller wants us to raise status */ RtlRaiseStatus(STATUS_INVALID_PARAMETER_1); @@ -136,7 +133,7 @@ LdrLockLoaderLock(IN ULONG Flags, if (!Cookie) { /* No cookie check how to fail */ - if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_STATUS) + if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS) { /* The caller wants us to raise status */ RtlRaiseStatus(STATUS_INVALID_PARAMETER_3); @@ -150,7 +147,7 @@ LdrLockLoaderLock(IN ULONG Flags, if ((Flags & LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY) && !(Result)) { /* No pointer to return the data to */ - if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_STATUS) + if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS) { /* The caller wants us to raise status */ RtlRaiseStatus(STATUS_INVALID_PARAMETER_2); @@ -164,7 +161,7 @@ LdrLockLoaderLock(IN ULONG Flags, if (InInit) return STATUS_SUCCESS; /* Check what locking semantic to use */ - if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_STATUS) + if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS) { /* Check if we should enter or simply try */ if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY) @@ -173,13 +170,13 @@ LdrLockLoaderLock(IN ULONG Flags, if (!RtlTryEnterCriticalSection(&LdrpLoaderLock)) { /* It's locked */ - *Result = LDR_LOCK_HELD; + *Result = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_NOT_ACQUIRED; goto Quickie; } else { /* It worked */ - *Result = LDR_LOCK_FREE; + *Result = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED; } } else @@ -188,7 +185,7 @@ LdrLockLoaderLock(IN ULONG Flags, RtlEnterCriticalSection(&LdrpLoaderLock); /* See if result was requested */ - if (Result) *Result = LDR_LOCK_FREE; + if (Result) *Result = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED; } /* Increase the acquisition count */ @@ -209,13 +206,13 @@ LdrLockLoaderLock(IN ULONG Flags, if (!RtlTryEnterCriticalSection(&LdrpLoaderLock)) { /* It's locked */ - *Result = LDR_LOCK_HELD; + *Result = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_NOT_ACQUIRED; _SEH2_YIELD(return STATUS_SUCCESS); } else { /* It worked */ - *Result = LDR_LOCK_FREE; + *Result = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED; } } else @@ -224,7 +221,7 @@ LdrLockLoaderLock(IN ULONG Flags, RtlEnterCriticalSection(&LdrpLoaderLock); /* See if result was requested */ - if (Result) *Result = LDR_LOCK_FREE; + if (Result) *Result = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED; } /* Increase the acquisition count */ @@ -530,4 +527,66 @@ LdrQueryProcessModuleInformation(IN PRTL_PROCESS_MODULES ModuleInformation, return LdrQueryProcessModuleInformationEx(0, 0, ModuleInformation, Size, ReturnedSize); } +NTSTATUS +NTAPI +LdrEnumerateLoadedModules(BOOLEAN ReservedFlag, PLDR_ENUM_CALLBACK EnumProc, PVOID Context) +{ + PLIST_ENTRY ListHead, ListEntry; + PLDR_DATA_TABLE_ENTRY LdrEntry; + NTSTATUS Status; + ULONG Cookie; + BOOLEAN Stop = FALSE; + + /* Check parameters */ + if (ReservedFlag || !EnumProc) return STATUS_INVALID_PARAMETER; + + /* Acquire the loader lock */ + Status = LdrLockLoaderLock(0, NULL, &Cookie); + if (!NT_SUCCESS(Status)) return Status; + + /* Loop all the modules and call enum proc */ + ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList; + ListEntry = ListHead->Flink; + while (ListHead != ListEntry) + { + /* Get the entry */ + LdrEntry = CONTAINING_RECORD(ListEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); + + /* Call the enumeration proc inside SEH */ + _SEH2_TRY + { + EnumProc(LdrEntry, Context, &Stop); + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + /* Ignoring the exception */ + } _SEH2_END; + + /* Break if we were asked to stop enumeration */ + if (Stop) + { + /* Release loader lock */ + Status = LdrUnlockLoaderLock(0, Cookie); + + /* Reset any successful status to STATUS_SUCCESS, but leave + failure to the caller */ + if (NT_SUCCESS(Status)) + Status = STATUS_SUCCESS; + + /* Return any possible failure status */ + return Status; + } + + /* Advance to the next module */ + ListEntry = ListEntry->Flink; + } + + /* Release loader lock, it must succeed this time */ + Status = LdrUnlockLoaderLock(0, Cookie); + ASSERT(NT_SUCCESS(Status)); + + /* Return success */ + return STATUS_SUCCESS; +} + /* EOF */ diff --git a/dll/ntdll/ldr/ldrinit.c b/dll/ntdll/ldr/ldrinit.c index cccaa4ee4f3..5913304361a 100644 --- a/dll/ntdll/ldr/ldrinit.c +++ b/dll/ntdll/ldr/ldrinit.c @@ -786,8 +786,8 @@ LdrpAllocateTls(VOID) PVOID *TlsVector; /* Check if we have any entries */ - if (LdrpNumberOfTlsEntries) - return 0; + if (!LdrpNumberOfTlsEntries) + return STATUS_SUCCESS; /* Allocate the vector array */ TlsVector = RtlAllocateHeap(RtlGetProcessHeap(), diff --git a/dll/ntdll/ldr/utils.c b/dll/ntdll/ldr/utils.c index c9bb89bbb51..9ce0cbb9feb 100644 --- a/dll/ntdll/ldr/utils.c +++ b/dll/ntdll/ldr/utils.c @@ -1350,7 +1350,7 @@ RtlpRaiseImportNotFound(CHAR *FuncName, ULONG Ordinal, PUNICODE_STRING DllName) ULONG ErrorResponse; ULONG_PTR ErrorParameters[2]; ANSI_STRING ProcNameAnsi; - UNICODE_STRING ProcName; + ANSI_STRING DllNameAnsi; CHAR Buffer[8]; if (!FuncName) @@ -1360,16 +1360,16 @@ RtlpRaiseImportNotFound(CHAR *FuncName, ULONG Ordinal, PUNICODE_STRING DllName) } RtlInitAnsiString(&ProcNameAnsi, FuncName); - RtlAnsiStringToUnicodeString(&ProcName, &ProcNameAnsi, TRUE); - ErrorParameters[0] = (ULONG_PTR)&ProcName; - ErrorParameters[1] = (ULONG_PTR)DllName; + RtlUnicodeStringToAnsiString(&DllNameAnsi, DllName, TRUE); + ErrorParameters[0] = (ULONG_PTR)&ProcNameAnsi; + ErrorParameters[1] = (ULONG_PTR)&DllNameAnsi; NtRaiseHardError(STATUS_ENTRYPOINT_NOT_FOUND, 2, 3, ErrorParameters, OptionOk, &ErrorResponse); - RtlFreeUnicodeString(&ProcName); + RtlFreeAnsiString(&DllNameAnsi); } static NTSTATUS diff --git a/dll/ntdll/rtl/libsupp.c b/dll/ntdll/rtl/libsupp.c index 4239183c436..f3e685c10af 100644 --- a/dll/ntdll/rtl/libsupp.c +++ b/dll/ntdll/rtl/libsupp.c @@ -519,3 +519,22 @@ RtlPcToFileHeader(IN PVOID PcValue, *BaseOfImage = ImageBase; return ImageBase; } + +NTSYSAPI +NTSTATUS +NTAPI +RtlDosApplyFileIsolationRedirection_Ustr( + IN BOOLEAN Unknown, + IN PUNICODE_STRING OriginalName, + IN PUNICODE_STRING Extension, + IN OUT PUNICODE_STRING RedirectedName, + IN OUT PUNICODE_STRING RedirectedName2, + IN OUT PUNICODE_STRING *OriginalName2, + IN PVOID Unknown1, + IN PVOID Unknown2, + IN PVOID Unknown3 +) +{ + return STATUS_SXS_KEY_NOT_FOUND; +} + diff --git a/dll/win32/advapi32/reg/reg.c b/dll/win32/advapi32/reg/reg.c index c6af98b5b4f..cfc8ba1ea28 100644 --- a/dll/win32/advapi32/reg/reg.c +++ b/dll/win32/advapi32/reg/reg.c @@ -3988,7 +3988,7 @@ RegQueryValueExA(HKEY hKey, LPDWORD lpcbData) { UNICODE_STRING ValueName; - UNICODE_STRING ValueData; + LPWSTR lpValueBuffer; LONG ErrorCode; DWORD Length; DWORD Type; @@ -4003,39 +4003,42 @@ RegQueryValueExA(HKEY hKey, return ERROR_INVALID_PARAMETER; } + Length = (lpcbData == NULL || lpData == NULL) ? 0 : *lpcbData * sizeof(WCHAR); + if (lpData) { - ValueData.Length = 0; - ValueData.MaximumLength = (*lpcbData + 1) * sizeof(WCHAR); - ValueData.Buffer = RtlAllocateHeap(ProcessHeap, - 0, - ValueData.MaximumLength); - if (!ValueData.Buffer) + lpValueBuffer = RtlAllocateHeap(ProcessHeap, + 0, + Length + sizeof(WCHAR)); + if (!lpValueBuffer) { return ERROR_OUTOFMEMORY; } } else { - ValueData.Buffer = NULL; - ValueData.Length = 0; - ValueData.MaximumLength = 0; + lpValueBuffer = NULL; if (lpcbData) *lpcbData = 0; } - RtlCreateUnicodeStringFromAsciiz(&ValueName, - (LPSTR)lpValueName); + if(!RtlCreateUnicodeStringFromAsciiz(&ValueName, + (LPSTR)lpValueName)) + { + ERR("RtlCreateUnicodeStringFromAsciiz failed!\n"); + ErrorCode = ERROR_OUTOFMEMORY; + goto cleanup; + } - Length = (lpcbData == NULL) ? 0 : *lpcbData * sizeof(WCHAR); ErrorCode = RegQueryValueExW(hKey, ValueName.Buffer, lpReserved, &Type, - (lpData == NULL) ? NULL : (LPBYTE)ValueData.Buffer, + (LPBYTE)lpValueBuffer, &Length); TRACE("ErrorCode %lu\n", ErrorCode); + RtlFreeUnicodeString(&ValueName); if (ErrorCode == ERROR_SUCCESS || @@ -4044,9 +4047,9 @@ RegQueryValueExA(HKEY hKey, if (is_string(Type)) { - if (ErrorCode == ERROR_SUCCESS && ValueData.Buffer != NULL) + if (ErrorCode == ERROR_SUCCESS && lpValueBuffer != NULL) { - Status = RtlUnicodeToMultiByteN((PCHAR)lpData, *lpcbData, &Index, (PWCHAR)ValueData.Buffer, Length); + Status = RtlUnicodeToMultiByteN((PCHAR)lpData, *lpcbData, &Index, (PWCHAR)lpValueBuffer, Length); if (NT_SUCCESS(Status)) { PCHAR szData = (PCHAR)lpData; @@ -4063,7 +4066,7 @@ RegQueryValueExA(HKEY hKey, Length = Length / sizeof(WCHAR); } - else if (ErrorCode == ERROR_SUCCESS && ValueData.Buffer != NULL) + else if (ErrorCode == ERROR_SUCCESS && lpValueBuffer != NULL) { if (*lpcbData < Length) { @@ -4071,7 +4074,7 @@ RegQueryValueExA(HKEY hKey, } else { - RtlMoveMemory(lpData, ValueData.Buffer, Length); + RtlMoveMemory(lpData, lpValueBuffer, Length); } } @@ -4086,9 +4089,10 @@ RegQueryValueExA(HKEY hKey, *lpType = Type; } - if (ValueData.Buffer != NULL) +cleanup: + if (lpValueBuffer != NULL) { - RtlFreeHeap(ProcessHeap, 0, ValueData.Buffer); + RtlFreeHeap(ProcessHeap, 0, lpValueBuffer); } return ErrorCode; diff --git a/dll/win32/advapi32/sec/lsa.c b/dll/win32/advapi32/sec/lsa.c index 246fbc5ae29..ec76774bbfd 100644 --- a/dll/win32/advapi32/sec/lsa.c +++ b/dll/win32/advapi32/sec/lsa.c @@ -430,20 +430,22 @@ LsaLookupNames(IN LSA_HANDLE PolicyHandle, OUT PLSA_REFERENCED_DOMAIN_LIST *ReferencedDomains, OUT PLSA_TRANSLATED_SID *Sids) { - LSAPR_TRANSLATED_SIDS TranslatedSids; + LSAPR_TRANSLATED_SIDS TranslatedSids = {0, NULL}; ULONG MappedCount = 0; NTSTATUS Status; TRACE("(%p,0x%08x,%p,%p,%p)\n", PolicyHandle, Count, Names, ReferencedDomains, Sids); + if (ReferencedDomains == NULL || Sids == NULL) + return STATUS_INVALID_PARAMETER; + RpcTryExcept { *ReferencedDomains = NULL; *Sids = NULL; TranslatedSids.Entries = Count; - TranslatedSids.Sids = *Sids; Status = LsarLookupNames((LSAPR_HANDLE)PolicyHandle, Count, @@ -458,9 +460,7 @@ LsaLookupNames(IN LSA_HANDLE PolicyHandle, RpcExcept(EXCEPTION_EXECUTE_HANDLER) { if (TranslatedSids.Sids != NULL) - { MIDL_user_free(TranslatedSids.Sids); - } Status = I_RpcMapWin32Status(RpcExceptionCode()); } @@ -471,27 +471,56 @@ LsaLookupNames(IN LSA_HANDLE PolicyHandle, /* - * @unimplemented + * @implemented */ NTSTATUS WINAPI -LsaLookupNames2( - LSA_HANDLE PolicyHandle, - ULONG Flags, - ULONG Count, - PLSA_UNICODE_STRING Names, - PLSA_REFERENCED_DOMAIN_LIST *ReferencedDomains, - PLSA_TRANSLATED_SID2 *Sids) +LsaLookupNames2(IN LSA_HANDLE PolicyHandle, + IN ULONG Flags, + IN ULONG Count, + IN PLSA_UNICODE_STRING Names, + OUT PLSA_REFERENCED_DOMAIN_LIST *ReferencedDomains, + OUT PLSA_TRANSLATED_SID2 *Sids) { - FIXME("(%p,0x%08x,0x%08x,%p,%p,%p) stub\n", PolicyHandle, Flags, - Count, Names, ReferencedDomains, Sids); - if (Names != NULL && Count > 0) + LSAPR_TRANSLATED_SIDS_EX2 TranslatedSids = {0, NULL}; + ULONG MappedCount = 0; + NTSTATUS Status; + + TRACE("(%p,0x%08x,0x%08x,%p,%p,%p) stub\n", PolicyHandle, Flags, + Count, Names, ReferencedDomains, Sids); + + if (ReferencedDomains == NULL || Sids == NULL) + return STATUS_INVALID_PARAMETER; + + RpcTryExcept { - *ReferencedDomains = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(LSA_REFERENCED_DOMAIN_LIST)); - *Sids = RtlAllocateHeap(RtlGetProcessHeap(), 0, Count * sizeof(LSA_TRANSLATED_SID2)); - return STATUS_SOME_NOT_MAPPED; + *ReferencedDomains = NULL; + *Sids = NULL; + + TranslatedSids.Entries = Count; + + Status = LsarLookupNames3((LSAPR_HANDLE)PolicyHandle, + Count, + (PRPC_UNICODE_STRING)Names, + (PLSAPR_REFERENCED_DOMAIN_LIST *)ReferencedDomains, + &TranslatedSids, + LsapLookupWksta, + &MappedCount, + Flags, + 2); + + *Sids = (PLSA_TRANSLATED_SID2)TranslatedSids.Sids; } - return STATUS_NONE_MAPPED; + RpcExcept(EXCEPTION_EXECUTE_HANDLER) + { + if (TranslatedSids.Sids != NULL) + MIDL_user_free(TranslatedSids.Sids); + + Status = I_RpcMapWin32Status(RpcExceptionCode()); + } + RpcEndExcept; + + return Status; } @@ -762,6 +791,7 @@ LsaQueryDomainInformationPolicy( return STATUS_NOT_IMPLEMENTED; } + /* * @unimplemented */ diff --git a/dll/win32/gdi32/misc/misc.c b/dll/win32/gdi32/misc/misc.c index 8fedb8fb820..dac9a73a8ff 100644 --- a/dll/win32/gdi32/misc/misc.c +++ b/dll/win32/gdi32/misc/misc.c @@ -275,7 +275,7 @@ HGDIOBJ FASTCALL hGetPEBHandle(HANDLECACHETYPE Type, COLORREF cr) { - int Number; + int Number, Offset, MaxNum, GdiType; HANDLE Lock; HGDIOBJ Handle = NULL; @@ -287,26 +287,58 @@ hGetPEBHandle(HANDLECACHETYPE Type, COLORREF cr) Number = GdiHandleCache->ulNumHandles[Type]; - if ( Number && Number <= CACHE_REGION_ENTRIES ) + if (Type == hctBrushHandle) { - if ( Type == hctRegionHandle) - { - PRGN_ATTR pRgn_Attr; - HGDIOBJ *hPtr; - hPtr = GdiHandleCache->Handle + CACHE_BRUSH_ENTRIES+CACHE_PEN_ENTRIES; - Handle = hPtr[Number - 1]; + Offset = 0; + MaxNum = CACHE_BRUSH_ENTRIES; + GdiType = GDILoObjType_LO_BRUSH_TYPE; + } + else if (Type == hctPenHandle) + { + Offset = CACHE_BRUSH_ENTRIES; + MaxNum = CACHE_PEN_ENTRIES; + GdiType = GDILoObjType_LO_PEN_TYPE; + } + else if (Type == hctRegionHandle) + { + Offset = CACHE_BRUSH_ENTRIES+CACHE_PEN_ENTRIES; + MaxNum = CACHE_REGION_ENTRIES; + GdiType = GDILoObjType_LO_REGION_TYPE; + } + else // Font is not supported here. + { + return Handle; + } - if (GdiGetHandleUserData( Handle, GDI_OBJECT_TYPE_REGION, (PVOID) &pRgn_Attr)) - { - if (pRgn_Attr->AttrFlags & ATTR_CACHED) + if ( Number && Number <= MaxNum ) + { + PBRUSH_ATTR pBrush_Attr; + HGDIOBJ *hPtr; + hPtr = GdiHandleCache->Handle + Offset; + Handle = hPtr[Number - 1]; + + if (GdiGetHandleUserData( Handle, GdiType, (PVOID) &pBrush_Attr)) + { + if (pBrush_Attr->AttrFlags & ATTR_CACHED) + { + DPRINT("Get Handle! Type %d Count %d PEB 0x%x\n", Type, GdiHandleCache->ulNumHandles[Type], NtCurrentTeb()->ProcessEnvironmentBlock); + pBrush_Attr->AttrFlags &= ~ATTR_CACHED; + hPtr[Number - 1] = NULL; + GdiHandleCache->ulNumHandles[Type]--; + if ( Type == hctBrushHandle ) // Handle only brush. + { + if ( pBrush_Attr->lbColor != cr ) { - DPRINT("Get Handle! Count %d PEB 0x%x\n", GdiHandleCache->ulNumHandles[Type], NtCurrentTeb()->ProcessEnvironmentBlock); - pRgn_Attr->AttrFlags &= ~ATTR_CACHED; - hPtr[Number - 1] = NULL; - GdiHandleCache->ulNumHandles[Type]--; + pBrush_Attr->lbColor = cr ; + pBrush_Attr->AttrFlags |= ATTR_NEW_COLOR; } - } - } + } + } + } + else + { + Handle = NULL; + } } (void)InterlockedExchangePointer((PVOID*)&GdiHandleCache->ulLock, Lock); return Handle; diff --git a/dll/win32/gdi32/objects/brush.c b/dll/win32/gdi32/objects/brush.c index 185bed6c3fb..e1b7f2951e5 100644 --- a/dll/win32/gdi32/objects/brush.c +++ b/dll/win32/gdi32/objects/brush.c @@ -234,6 +234,8 @@ CreateBrushIndirect( break; case BS_SOLID: +/* hBrush = hGetPEBHandle(hctBrushHandle, LogBrush->lbColor); + if (!hBrush)*/ hBrush = NtGdiCreateSolidBrush(LogBrush->lbColor, 0); break; diff --git a/dll/win32/gdi32/objects/pen.c b/dll/win32/gdi32/objects/pen.c index 0a431c20049..dbbe0f2de2b 100644 --- a/dll/win32/gdi32/objects/pen.c +++ b/dll/win32/gdi32/objects/pen.c @@ -23,12 +23,34 @@ CreatePen( int nWidth, COLORREF crColor) { - /* FIXME Some part need be done in user mode */ +/* HPEN hPen; + PBRUSH_ATTR Pen_Attr; +*/ + if (nPenStyle < PS_SOLID) nPenStyle = PS_SOLID; if (nPenStyle > PS_DASHDOTDOT) { if (nPenStyle == PS_NULL) return GetStockObject(NULL_PEN); if (nPenStyle != PS_INSIDEFRAME) nPenStyle = PS_SOLID; } +#if 0 + hPen = hGetPEBHandle(hctPenHandle, nPenStyle); + if ( nWidth || nPenStyle || !hPen ) + { + return NtGdiCreatePen(nPenStyle, nWidth, crColor, NULL); + } + + if ((GdiGetHandleUserData( hPen, GDI_OBJECT_TYPE_PEN, (PVOID) &Pen_Attr)) && + ( Pen_Attr != NULL )) + { + if ( Pen_Attr->lbColor != crColor) + { + Pen_Attr->lbColor = crColor; + Pen_Attr->AttrFlags |= ATTR_NEW_COLOR; + } + return hPen; + } + DeleteObject(hPen); +#endif return NtGdiCreatePen(nPenStyle, nWidth, crColor, NULL); } diff --git a/dll/win32/kernel32/file/curdir.c b/dll/win32/kernel32/file/curdir.c index 8c74fbe11a1..42ae057f054 100644 --- a/dll/win32/kernel32/file/curdir.c +++ b/dll/win32/kernel32/file/curdir.c @@ -28,6 +28,8 @@ DEBUG_CHANNEL(kernel32file); UNICODE_STRING SystemDirectory; UNICODE_STRING WindowsDirectory; +UNICODE_STRING BaseDefaultPathAppend; +UNICODE_STRING BaseDefaultPath; /* FUNCTIONS *****************************************************************/ diff --git a/dll/win32/kernel32/file/dir.c b/dll/win32/kernel32/file/dir.c index a364e6a1f46..184403912f3 100644 --- a/dll/win32/kernel32/file/dir.c +++ b/dll/win32/kernel32/file/dir.c @@ -20,7 +20,7 @@ #include DEBUG_CHANNEL(kernel32file); -UNICODE_STRING DllDirectory = {0, 0, NULL}; +UNICODE_STRING BaseDllDirectory = {0, 0, NULL}; /* FUNCTIONS *****************************************************************/ @@ -1079,35 +1079,35 @@ SetDllDirectoryW( RtlInitUnicodeString(&PathName, lpPathName); - RtlEnterCriticalSection(&DllLock); + RtlEnterCriticalSection(&BaseDllDirectoryLock); if(PathName.Length > 0) { - if(PathName.Length + sizeof(WCHAR) <= DllDirectory.MaximumLength) + if(PathName.Length + sizeof(WCHAR) <= BaseDllDirectory.MaximumLength) { - RtlCopyUnicodeString(&DllDirectory, &PathName); + RtlCopyUnicodeString(&BaseDllDirectory, &PathName); } else { - RtlFreeUnicodeString(&DllDirectory); - if(!(DllDirectory.Buffer = (PWSTR)RtlAllocateHeap(RtlGetProcessHeap(), - 0, - PathName.Length + sizeof(WCHAR)))) + RtlFreeUnicodeString(&BaseDllDirectory); + if(!(BaseDllDirectory.Buffer = (PWSTR)RtlAllocateHeap(RtlGetProcessHeap(), + 0, + PathName.Length + sizeof(WCHAR)))) { - RtlLeaveCriticalSection(&DllLock); + RtlLeaveCriticalSection(&BaseDllDirectoryLock); SetLastError(ERROR_NOT_ENOUGH_MEMORY); return FALSE; } - DllDirectory.Length = 0; - DllDirectory.MaximumLength = PathName.Length + sizeof(WCHAR); + BaseDllDirectory.Length = 0; + BaseDllDirectory.MaximumLength = PathName.Length + sizeof(WCHAR); - RtlCopyUnicodeString(&DllDirectory, &PathName); + RtlCopyUnicodeString(&BaseDllDirectory, &PathName); } } else { - RtlFreeUnicodeString(&DllDirectory); + RtlFreeUnicodeString(&BaseDllDirectory); } - RtlLeaveCriticalSection(&DllLock); + RtlLeaveCriticalSection(&BaseDllDirectoryLock); return TRUE; } @@ -1144,10 +1144,10 @@ GetDllDirectoryW( { DWORD Ret; - RtlEnterCriticalSection(&DllLock); + RtlEnterCriticalSection(&BaseDllDirectoryLock); if(nBufferLength > 0) { - Ret = DllDirectory.Length / sizeof(WCHAR); + Ret = BaseDllDirectory.Length / sizeof(WCHAR); if(Ret > nBufferLength - 1) { Ret = nBufferLength - 1; @@ -1155,16 +1155,16 @@ GetDllDirectoryW( if(Ret > 0) { - RtlCopyMemory(lpBuffer, DllDirectory.Buffer, Ret * sizeof(WCHAR)); + RtlCopyMemory(lpBuffer, BaseDllDirectory.Buffer, Ret * sizeof(WCHAR)); } lpBuffer[Ret] = L'\0'; } else { /* include termination character, even if the string is empty! */ - Ret = (DllDirectory.Length / sizeof(WCHAR)) + 1; + Ret = (BaseDllDirectory.Length / sizeof(WCHAR)) + 1; } - RtlLeaveCriticalSection(&DllLock); + RtlLeaveCriticalSection(&BaseDllDirectoryLock); return Ret; } diff --git a/dll/win32/kernel32/include/kernel32.h b/dll/win32/kernel32/include/kernel32.h index 747c8b1b664..ef74e9e69ad 100755 --- a/dll/win32/kernel32/include/kernel32.h +++ b/dll/win32/kernel32/include/kernel32.h @@ -91,9 +91,11 @@ extern HANDLE hProcessHeap; extern HANDLE hBaseDir; extern HMODULE hCurrentModule; -extern RTL_CRITICAL_SECTION DllLock; +extern RTL_CRITICAL_SECTION BaseDllDirectoryLock; -extern UNICODE_STRING DllDirectory; +extern UNICODE_STRING BaseDllDirectory; +extern UNICODE_STRING BaseDefaultPath; +extern UNICODE_STRING BaseDefaultPathAppend; extern LPTOP_LEVEL_EXCEPTION_FILTER GlobalTopLevelExceptionFilter; @@ -211,6 +213,12 @@ BasepMapFile(IN LPCWSTR lpApplicationName, OUT PHANDLE hSection, IN PUNICODE_STRING ApplicationName); +LPWSTR +WINAPI +BasepGetDllPath(LPWSTR FullPath, + PVOID Environment); + + PCODEPAGE_ENTRY FASTCALL IntGetCodePageEntry(UINT CodePage); diff --git a/dll/win32/kernel32/misc/console.c b/dll/win32/kernel32/misc/console.c index 2b0d253b23e..2fc95b58d5f 100644 --- a/dll/win32/kernel32/misc/console.c +++ b/dll/win32/kernel32/misc/console.c @@ -3524,7 +3524,7 @@ SetConsoleCtrlHandler(PHANDLER_ROUTINE HandlerRoutine, { BOOL Ret; - RtlEnterCriticalSection(&DllLock); + RtlEnterCriticalSection(&BaseDllDirectoryLock); if (Add) { Ret = AddConsoleCtrlHandler(HandlerRoutine); @@ -3534,7 +3534,7 @@ SetConsoleCtrlHandler(PHANDLER_ROUTINE HandlerRoutine, Ret = RemoveConsoleCtrlHandler(HandlerRoutine); } - RtlLeaveCriticalSection(&DllLock); + RtlLeaveCriticalSection(&BaseDllDirectoryLock); return(Ret); } diff --git a/dll/win32/kernel32/misc/dllmain.c b/dll/win32/kernel32/misc/dllmain.c index ae0ada2e85c..c29a1828481 100644 --- a/dll/win32/kernel32/misc/dllmain.c +++ b/dll/win32/kernel32/misc/dllmain.c @@ -5,6 +5,7 @@ * FILE: lib/kernel32/misc/dllmain.c * PURPOSE: Initialization * PROGRAMMER: Ariadne ( ariadne@xs4all.nl) + * Aleksey Bragin (aleksey@reactos.org) * UPDATE HISTORY: * Created 01/11/98 */ @@ -21,6 +22,8 @@ extern UNICODE_STRING SystemDirectory; extern UNICODE_STRING WindowsDirectory; +WCHAR BaseDefaultPathBuffer[6140]; + HANDLE hProcessHeap = NULL; HMODULE hCurrentModule = NULL; HANDLE hBaseDir = NULL; @@ -36,7 +39,7 @@ DllMain(HANDLE hInst, LPVOID lpReserved); /* Critical section for various kernel32 data structures */ -RTL_CRITICAL_SECTION DllLock; +RTL_CRITICAL_SECTION BaseDllDirectoryLock; RTL_CRITICAL_SECTION ConsoleLock; extern BOOL WINAPI DefaultConsoleCtrlHandler(DWORD Event); @@ -275,6 +278,9 @@ DllMain(HANDLE hDll, /* Don't bother us for each thread */ LdrDisableThreadCalloutsForDll((PVOID)hDll); + /* Initialize default path to NULL */ + RtlInitUnicodeString(&BaseDefaultPath, NULL); + /* Setup the right Object Directory path */ if (!SessionId) { @@ -332,11 +338,25 @@ DllMain(HANDLE hDll, SystemDirectory.MaximumLength); if(SystemDirectory.Buffer == NULL) { + DPRINT1("Failure allocating SystemDirectory buffer\n"); return FALSE; } wcscpy(SystemDirectory.Buffer, WindowsDirectory.Buffer); wcscat(SystemDirectory.Buffer, L"\\System32"); + /* Construct the default path (using the static buffer) */ + _snwprintf(BaseDefaultPathBuffer, sizeof(BaseDefaultPathBuffer) / sizeof(WCHAR), + L".;%wZ;%wZ\\system;%wZ;", &SystemDirectory, &WindowsDirectory, &WindowsDirectory); + + BaseDefaultPath.Buffer = BaseDefaultPathBuffer; + BaseDefaultPath.Length = wcslen(BaseDefaultPathBuffer) * sizeof(WCHAR); + BaseDefaultPath.MaximumLength = sizeof(BaseDefaultPathBuffer); + + /* Use remaining part of the default path buffer for the append path */ + BaseDefaultPathAppend.Buffer = (PWSTR)((ULONG_PTR)BaseDefaultPathBuffer + BaseDefaultPath.Length); + BaseDefaultPathAppend.Length = 0; + BaseDefaultPathAppend.MaximumLength = BaseDefaultPath.MaximumLength - BaseDefaultPath.Length; + /* Initialize command line */ InitCommandLines(); @@ -349,7 +369,7 @@ DllMain(HANDLE hDll, } /* Initialize the DLL critical section */ - RtlInitializeCriticalSection(&DllLock); + RtlInitializeCriticalSection(&BaseDllDirectoryLock); /* Initialize the National Language Support routines */ if (!NlsInit()) @@ -395,7 +415,7 @@ DllMain(HANDLE hDll, ConsoleInitialized = FALSE; RtlDeleteCriticalSection (&ConsoleLock); } - RtlDeleteCriticalSection (&DllLock); + RtlDeleteCriticalSection (&BaseDllDirectoryLock); /* Close object base directory */ NtClose(hBaseDir); diff --git a/dll/win32/kernel32/misc/ldr.c b/dll/win32/kernel32/misc/ldr.c index decc300fbab..cbf00e56896 100644 --- a/dll/win32/kernel32/misc/ldr.c +++ b/dll/win32/kernel32/misc/ldr.c @@ -1,10 +1,10 @@ -/* $Id$ - * +/* * COPYRIGHT: See COPYING in the top level directory * PROJECT : ReactOS user mode libraries * MODULE : kernel32.dll - * FILE : reactos/lib/kernel32/misc/ldr.c - * AUTHOR : Ariadne + * FILE : reactos/dll/win32/kernel32/misc/ldr.c + * AUTHOR : Aleksey Bragin + * Ariadne */ #include @@ -22,8 +22,68 @@ typedef struct tagLOADPARMS32 { extern BOOLEAN InWindows; extern WaitForInputIdleType lpfnGlobalRegisterWaitForInputIdle; +#define BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_ERROR 1 +#define BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_SUCCESS 2 +#define BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_CONTINUE 3 + /* FUNCTIONS ****************************************************************/ +DWORD +WINAPI +BasepGetModuleHandleExParameterValidation(DWORD dwFlags, + LPCWSTR lpwModuleName, + HMODULE *phModule) +{ + /* Set phModule to 0 if it's not a NULL pointer */ + if (phModule) *phModule = 0; + + /* Check for invalid flags combination */ + if (dwFlags & ~(GET_MODULE_HANDLE_EX_FLAG_PIN | + GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT | + GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS) || + ((dwFlags & GET_MODULE_HANDLE_EX_FLAG_PIN) && + (dwFlags & GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT)) || + (!lpwModuleName && (dwFlags & GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS)) + ) + { + BaseSetLastNTError(STATUS_INVALID_PARAMETER_1); + return BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_ERROR; + } + + /* Check 2nd parameter */ + if (!phModule) + { + BaseSetLastNTError(STATUS_INVALID_PARAMETER_2); + return BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_ERROR; + } + + /* Return what we have according to the module name */ + if (lpwModuleName) + { + return BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_CONTINUE; + } + + /* No name given, so put ImageBaseAddress there */ + *phModule = (HMODULE)NtCurrentPeb()->ImageBaseAddress; + + return BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_SUCCESS; +} + +PVOID +WINAPI +BasepMapModuleHandle(HMODULE hModule, BOOLEAN AsDataFile) +{ + /* If no handle is provided - use current image base address */ + if (!hModule) return NtCurrentPeb()->ImageBaseAddress; + + /* Check if it's a normal or a datafile one */ + if (LDR_IS_DATAFILE(hModule) && !AsDataFile) + return NULL; + + /* It'a a normal DLL, just return its handle */ + return hModule; +} + /** * @name GetDllLoadPath * @@ -220,7 +280,7 @@ LoadLibraryExW ( HINSTANCE hInst; NTSTATUS Status; PWSTR SearchPath; - ULONG DllCharacteristics; + ULONG DllCharacteristics = 0; BOOL FreeString = FALSE; (void)hFile; @@ -349,27 +409,49 @@ GetProcAddress( HMODULE hModule, LPCSTR lpProcName ) BOOL WINAPI FreeLibrary(HINSTANCE hLibModule) { NTSTATUS Status; + PIMAGE_NT_HEADERS NtHeaders; - if (!hLibModule) + if (LDR_IS_DATAFILE(hLibModule)) { - SetLastError(ERROR_INVALID_HANDLE); - return FALSE; + // FIXME: This SEH should go inside RtlImageNtHeader instead + _SEH2_TRY + { + /* This is a LOAD_LIBRARY_AS_DATAFILE module, check if it's a valid one */ + NtHeaders = RtlImageNtHeader((PVOID)((ULONG_PTR)hLibModule & ~1)); + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + NtHeaders = NULL; + } _SEH2_END + + if (NtHeaders) + { + /* Unmap view */ + Status = NtUnmapViewOfSection(NtCurrentProcess(), (PVOID)((ULONG_PTR)hLibModule & ~1)); + + /* Unload alternate resource module */ + LdrUnloadAlternateResourceModule(hLibModule); + } + else + Status = STATUS_INVALID_IMAGE_FORMAT; + } + else + { + /* Just unload it */ + Status = LdrUnloadDll((PVOID)hLibModule); } - if ((ULONG_PTR)hLibModule & 1) - { - /* this is a LOAD_LIBRARY_AS_DATAFILE module */ - char *ptr = (char *)hLibModule - 1; - return UnmapViewOfFile(ptr); - } - - Status = LdrUnloadDll(hLibModule); + /* Check what kind of status we got */ if (!NT_SUCCESS(Status)) { - SetLastErrorByStatus(Status); + /* Set last error */ + BaseSetLastNTError(Status); + + /* Return failure */ return FALSE; } + /* Return success */ return TRUE; } @@ -379,12 +461,30 @@ BOOL WINAPI FreeLibrary(HINSTANCE hLibModule) */ VOID WINAPI -FreeLibraryAndExitThread ( - HMODULE hLibModule, - DWORD dwExitCode - ) +FreeLibraryAndExitThread(HMODULE hLibModule, + DWORD dwExitCode) { - FreeLibrary(hLibModule); + NTSTATUS Status; + + if (LDR_IS_DATAFILE(hLibModule)) + { + /* This is a LOAD_LIBRARY_AS_DATAFILE module */ + if (RtlImageNtHeader((PVOID)((ULONG_PTR)hLibModule & ~1))) + { + /* Unmap view */ + Status = NtUnmapViewOfSection(NtCurrentProcess(), (PVOID)((ULONG_PTR)hLibModule & ~1)); + + /* Unload alternate resource module */ + LdrUnloadAlternateResourceModule(hLibModule); + } + } + else + { + /* Just unload it */ + Status = LdrUnloadDll((PVOID)hLibModule); + } + + /* Exit thread */ ExitThread(dwExitCode); } @@ -394,123 +494,292 @@ FreeLibraryAndExitThread ( */ DWORD WINAPI -GetModuleFileNameA ( - HINSTANCE hModule, - LPSTR lpFilename, - DWORD nSize - ) +GetModuleFileNameA(HINSTANCE hModule, + LPSTR lpFilename, + DWORD nSize) { - ANSI_STRING FileName; - PLIST_ENTRY ModuleListHead; - PLIST_ENTRY Entry; - PLDR_DATA_TABLE_ENTRY Module; - PPEB Peb; - ULONG Length = 0; + UNICODE_STRING FilenameW; + ANSI_STRING FilenameA; + NTSTATUS Status; + DWORD Length = 0, LengthToCopy; - Peb = NtCurrentPeb (); - RtlEnterCriticalSection (Peb->LoaderLock); + /* Allocate a unicode buffer */ + FilenameW.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, nSize * sizeof(WCHAR)); + if (!FilenameW.Buffer) + { + BaseSetLastNTError(STATUS_NO_MEMORY); + return 0; + } - if (hModule == NULL) - hModule = Peb->ImageBaseAddress; + /* Call unicode API */ + FilenameW.Length = GetModuleFileNameW(hModule, FilenameW.Buffer, nSize) * sizeof(WCHAR); + FilenameW.MaximumLength = FilenameW.Length + sizeof(WCHAR); - ModuleListHead = &Peb->Ldr->InLoadOrderModuleList; - Entry = ModuleListHead->Flink; + if (FilenameW.Length) + { + /* Convert to ansi string */ + Status = BasepUnicodeStringTo8BitString(&FilenameA, &FilenameW, TRUE); + if (!NT_SUCCESS(Status)) + { + /* Set last error, free string and retun failure */ + BaseSetLastNTError(Status); + RtlFreeUnicodeString(&FilenameW); + return 0; + } - while (Entry != ModuleListHead) - { - Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); - if (Module->DllBase == (PVOID)hModule) - { - Length = min(nSize, Module->FullDllName.Length / sizeof(WCHAR)); - FileName.Length = 0; - FileName.MaximumLength = (USHORT)Length * sizeof(WCHAR); - FileName.Buffer = lpFilename; + /* Calculate size to copy */ + Length = min(nSize, FilenameA.Length); - /* convert unicode string to ansi (or oem) */ - if (bIsFileApiAnsi) - RtlUnicodeStringToAnsiString (&FileName, - &Module->FullDllName, - FALSE); - else - RtlUnicodeStringToOemString (&FileName, - &Module->FullDllName, - FALSE); - - if (Length < nSize) - lpFilename[Length] = '\0'; - else - SetLastErrorByStatus (STATUS_BUFFER_TOO_SMALL); + /* Include terminating zero */ + if (nSize > Length) + LengthToCopy = Length + 1; + else + LengthToCopy = nSize; - RtlLeaveCriticalSection (Peb->LoaderLock); - return Length; - } + /* Now copy back to the caller amount he asked */ + RtlMoveMemory(lpFilename, FilenameA.Buffer, LengthToCopy); - Entry = Entry->Flink; - } + /* Free ansi filename */ + RtlFreeAnsiString(&FilenameA); + } - SetLastErrorByStatus (STATUS_DLL_NOT_FOUND); - RtlLeaveCriticalSection (Peb->LoaderLock); + /* Free unicode filename */ + RtlFreeHeap(RtlGetProcessHeap(), 0, FilenameW.Buffer); - return 0; + /* Return length copied */ + return Length; } - /* * @implemented */ DWORD WINAPI -GetModuleFileNameW ( - HINSTANCE hModule, - LPWSTR lpFilename, - DWORD nSize - ) +GetModuleFileNameW(HINSTANCE hModule, + LPWSTR lpFilename, + DWORD nSize) { - UNICODE_STRING FileName; - PLIST_ENTRY ModuleListHead; - PLIST_ENTRY Entry; - PLDR_DATA_TABLE_ENTRY Module; - PPEB Peb; - ULONG Length = 0; + PLIST_ENTRY ModuleListHead, Entry; + PLDR_DATA_TABLE_ENTRY Module; + ULONG Length = 0; + ULONG Cookie; + PPEB Peb; - Peb = NtCurrentPeb (); - RtlEnterCriticalSection (Peb->LoaderLock); + hModule = BasepMapModuleHandle(hModule, FALSE); - if (hModule == NULL) - hModule = Peb->ImageBaseAddress; + /* Upscale nSize from chars to bytes */ + nSize *= sizeof(WCHAR); - ModuleListHead = &Peb->Ldr->InLoadOrderModuleList; - Entry = ModuleListHead->Flink; - while (Entry != ModuleListHead) - { - Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); + _SEH2_TRY + { + /* We don't use per-thread cur dir now */ + //PRTL_PERTHREAD_CURDIR PerThreadCurdir = (PRTL_PERTHREAD_CURDIR)teb->NtTib.SubSystemTib; - if (Module->DllBase == (PVOID)hModule) - { - Length = min(nSize, Module->FullDllName.Length / sizeof(WCHAR)); - FileName.Length = 0; - FileName.MaximumLength = (USHORT) Length * sizeof(WCHAR); - FileName.Buffer = lpFilename; + Peb = NtCurrentPeb (); - RtlCopyUnicodeString (&FileName, - &Module->FullDllName); - if (Length < nSize) - lpFilename[Length] = L'\0'; - else - SetLastErrorByStatus (STATUS_BUFFER_TOO_SMALL); + /* Acquire a loader lock */ + LdrLockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, NULL, &Cookie); - RtlLeaveCriticalSection (Peb->LoaderLock); + /* Traverse the module list */ + ModuleListHead = &Peb->Ldr->InLoadOrderModuleList; + Entry = ModuleListHead->Flink; + while (Entry != ModuleListHead) + { + Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); - return Length; - } + /* Check if this is the requested module */ + if (Module->DllBase == (PVOID)hModule) + { + /* Calculate size to copy */ + Length = min(nSize, Module->FullDllName.MaximumLength); - Entry = Entry->Flink; - } + /* Copy contents */ + RtlMoveMemory(lpFilename, Module->FullDllName.Buffer, Length); - SetLastErrorByStatus (STATUS_DLL_NOT_FOUND); - RtlLeaveCriticalSection (Peb->LoaderLock); + /* Subtract a terminating zero */ + if (Length == Module->FullDllName.MaximumLength) + Length -= sizeof(WCHAR); - return 0; + /* Break out of the loop */ + break; + } + + /* Advance to the next entry */ + Entry = Entry->Flink; + } + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + BaseSetLastNTError(_SEH2_GetExceptionCode()); + Length = 0; + } _SEH2_END + + /* Release the loader lock */ + LdrUnlockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, Cookie); + + return Length / sizeof(WCHAR); +} + +HMODULE +WINAPI +GetModuleHandleForUnicodeString(PUNICODE_STRING ModuleName) +{ + NTSTATUS Status; + PVOID Module; + LPWSTR DllPath; + + /* Try to get a handle with a magic value of 1 for DllPath */ + Status = LdrGetDllHandle((LPWSTR)1, NULL, ModuleName, &Module); + + /* If that succeeded - we're done */ + if (NT_SUCCESS(Status)) return Module; + + /* If not, then the path should be computed */ + DllPath = BasepGetDllPath(NULL, 0); + + /* Call LdrGetHandle() again providing the computed DllPath + and wrapped into SEH */ + _SEH2_TRY + { + Status = LdrGetDllHandle(DllPath, NULL, ModuleName, &Module); + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + /* Fail with the SEH error */ + Status = _SEH2_GetExceptionCode(); + } + _SEH2_END; + + /* Free the DllPath */ + RtlFreeHeap(RtlGetProcessHeap(), 0, DllPath); + + /* In case of error set last win32 error and return NULL */ + if (!NT_SUCCESS(Status)) + { + DPRINT("Failure acquiring DLL module '%wZ' handle, Status 0x%08X\n", ModuleName, Status); + SetLastErrorByStatus(Status); + Module = 0; + } + + /* Return module */ + return (HMODULE)Module; +} + +BOOLEAN +WINAPI +BasepGetModuleHandleExW(BOOLEAN NoLock, DWORD dwPublicFlags, LPCWSTR lpwModuleName, HMODULE *phModule) +{ + DWORD Cookie; + NTSTATUS Status = STATUS_SUCCESS, Status2; + HANDLE hModule = 0; + UNICODE_STRING ModuleNameU; + DWORD dwValid; + BOOLEAN Redirected = FALSE; // FIXME + + /* Validate parameters */ + dwValid = BasepGetModuleHandleExParameterValidation(dwPublicFlags, lpwModuleName, phModule); + ASSERT(dwValid == BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_CONTINUE); + + /* Acquire lock if necessary */ + if (!NoLock) + { + Status = LdrLockLoaderLock(0, NULL, &Cookie); + if (!NT_SUCCESS(Status)) + { + /* Fail */ + SetLastErrorByStatus(Status); + if (phModule) *phModule = 0; + return Status; + } + } + + if (!(dwPublicFlags & GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS)) + { + /* Create a unicode string out of module name */ + RtlInitUnicodeString(&ModuleNameU, lpwModuleName); + + // FIXME: Do some redirected DLL stuff? + if (Redirected) + { + UNIMPLEMENTED; + } + + if (!hModule) + { + hModule = GetModuleHandleForUnicodeString(&ModuleNameU); + if (!hModule) + { + /* Last error is already set, so just return failure by setting status */ + Status = STATUS_DLL_NOT_FOUND; + goto quickie; + } + } + } + else + { + /* Perform Pc to file header to get module instance */ + hModule = (HMODULE)RtlPcToFileHeader((PVOID)lpwModuleName, + (PVOID*)&hModule); + + /* Check if it succeeded */ + if (!hModule) + { + /* Set "dll not found" status and quit */ + Status = STATUS_DLL_NOT_FOUND; + goto quickie; + } + } + + /* Check if changing reference is not forbidden */ + if (!(dwPublicFlags & GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT)) + { + /* Add reference to this DLL */ + Status = LdrAddRefDll((dwPublicFlags & GET_MODULE_HANDLE_EX_FLAG_PIN) ? LDR_PIN_MODULE : 0, + hModule); + } + + /* Set last error in case of failure */ + if (!NT_SUCCESS(Status)) + SetLastErrorByStatus(Status); + +quickie: + /* Unlock loader lock if it was acquired */ + if (!NoLock) + { + Status2 = LdrUnlockLoaderLock(0, Cookie); + ASSERT(NT_SUCCESS(Status2)); + } + + /* Set the module handle to the caller */ + if (phModule) *phModule = hModule; + + /* Return TRUE on success and FALSE otherwise */ + return NT_SUCCESS(Status); +} + +/* + * @implemented + */ +HMODULE +WINAPI +GetModuleHandleA(LPCSTR lpModuleName) +{ + PUNICODE_STRING ModuleNameW; + PTEB pTeb = NtCurrentTeb(); + + /* Check if we have no name to convert */ + if (!lpModuleName) + return ((HMODULE)pTeb->ProcessEnvironmentBlock->ImageBaseAddress); + + /* Convert module name to unicode */ + ModuleNameW = Basep8BitStringToStaticUnicodeString(lpModuleName); + + /* Call W version if conversion was successful */ + if (ModuleNameW) + return GetModuleHandleW(ModuleNameW->Buffer); + + /* Return failure */ + return 0; } @@ -519,61 +788,26 @@ GetModuleFileNameW ( */ HMODULE WINAPI -GetModuleHandleA ( LPCSTR lpModuleName ) +GetModuleHandleW(LPCWSTR lpModuleName) { - ANSI_STRING ModuleName; - NTSTATUS Status; - PTEB pTeb = NtCurrentTeb(); + HMODULE hModule; + NTSTATUS Status; - if (lpModuleName == NULL) - { - return ((HMODULE)pTeb->ProcessEnvironmentBlock->ImageBaseAddress); - } + /* If current module is requested - return it right away */ + if (!lpModuleName) + return ((HMODULE)NtCurrentPeb()->ImageBaseAddress); - RtlInitAnsiString(&ModuleName, lpModuleName); + /* Use common helper routine */ + Status = BasepGetModuleHandleExW(TRUE, + GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, + lpModuleName, + &hModule); - Status = RtlAnsiStringToUnicodeString(&pTeb->StaticUnicodeString, - &ModuleName, - FALSE); + /* If it wasn't successful - return 0 */ + if (!NT_SUCCESS(Status)) hModule = 0; - if (NT_SUCCESS(Status)) - { - return GetModuleHandleW(pTeb->StaticUnicodeString.Buffer); - } - - SetLastErrorByStatus(Status); - return FALSE; -} - - -/* - * @implemented - */ -HMODULE -WINAPI -GetModuleHandleW (LPCWSTR lpModuleName) -{ - UNICODE_STRING ModuleName; - PVOID BaseAddress; - NTSTATUS Status; - - if (lpModuleName == NULL) - return ((HMODULE)NtCurrentPeb()->ImageBaseAddress); - - RtlInitUnicodeString (&ModuleName, - (LPWSTR)lpModuleName); - - Status = LdrGetDllHandle (0, - 0, - &ModuleName, - &BaseAddress); - if (!NT_SUCCESS(Status)) - { - SetLastErrorByStatus (Status); - return NULL; - } - - return ((HMODULE)BaseAddress); + /* Return the handle */ + return hModule; } @@ -583,64 +817,31 @@ GetModuleHandleW (LPCWSTR lpModuleName) BOOL WINAPI GetModuleHandleExW(IN DWORD dwFlags, - IN LPCWSTR lpModuleName OPTIONAL, + IN LPCWSTR lpwModuleName OPTIONAL, OUT HMODULE* phModule) { - HMODULE hModule; NTSTATUS Status; + DWORD dwValid; BOOL Ret = FALSE; - if (phModule == NULL || - ((dwFlags & (GET_MODULE_HANDLE_EX_FLAG_PIN | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT)) == - (GET_MODULE_HANDLE_EX_FLAG_PIN | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT))) - { - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } + /* Validate parameters */ + dwValid = BasepGetModuleHandleExParameterValidation(dwFlags, lpwModuleName, phModule); - if (lpModuleName == NULL) - { - hModule = NtCurrentPeb()->ImageBaseAddress; - } - else - { - if (dwFlags & GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS) - { - hModule = (HMODULE)RtlPcToFileHeader((PVOID)lpModuleName, - (PVOID*)&hModule); - if (hModule == NULL) - { - SetLastErrorByStatus(STATUS_DLL_NOT_FOUND); - } - } - else - { - hModule = GetModuleHandleW(lpModuleName); - } - } + /* If result is invalid parameter - return failure */ + if (dwValid == BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_ERROR) return FALSE; - if (hModule != NULL) - { - if (!(dwFlags & GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT)) - { - Status = LdrAddRefDll((dwFlags & GET_MODULE_HANDLE_EX_FLAG_PIN) ? LDR_PIN_MODULE : 0, - hModule); + /* If result is 2, there is no need to do anything - return success. */ + if (dwValid == BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_SUCCESS) return TRUE; - if (NT_SUCCESS(Status)) - { - Ret = TRUE; - } - else - { - SetLastErrorByStatus(Status); - hModule = NULL; - } - } - else - Ret = TRUE; - } + /* Use common helper routine */ + Status = BasepGetModuleHandleExW(FALSE, + dwFlags, + lpwModuleName, + phModule); + + /* Return TRUE in case of success */ + if (NT_SUCCESS(Status)) Ret = TRUE; - *phModule = hModule; return Ret; } @@ -650,41 +851,52 @@ GetModuleHandleExW(IN DWORD dwFlags, BOOL WINAPI GetModuleHandleExA(IN DWORD dwFlags, - IN LPCSTR lpModuleName OPTIONAL, + IN LPCSTR lpModuleName OPTIONAL, OUT HMODULE* phModule) { - ANSI_STRING ModuleName; - LPCWSTR lpModuleNameW; + PUNICODE_STRING lpModuleNameW; + DWORD dwValid; + BOOL Ret = FALSE; NTSTATUS Status; - BOOL Ret; - PTEB pTeb = NtCurrentTeb(); + /* Validate parameters */ + dwValid = BasepGetModuleHandleExParameterValidation(dwFlags, (LPCWSTR)lpModuleName, phModule); + /* If result is invalid parameter - return failure */ + if (dwValid == BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_ERROR) return FALSE; + + /* If result is 2, there is no need to do anything - return success. */ + if (dwValid == BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_SUCCESS) return TRUE; + + /* Check if we don't need to convert the name */ if (dwFlags & GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS) { - lpModuleNameW = (LPCWSTR)lpModuleName; + /* Call the extended version of the API without conversion */ + Status = BasepGetModuleHandleExW(FALSE, + dwFlags, + (LPCWSTR)lpModuleName, + phModule); } else { - RtlInitAnsiString(&ModuleName, lpModuleName); + /* Convert module name to unicode */ + lpModuleNameW = Basep8BitStringToStaticUnicodeString(lpModuleName); - Status = RtlAnsiStringToUnicodeString(&pTeb->StaticUnicodeString, - &ModuleName, - FALSE); + /* Return FALSE if conversion failed */ + if (!lpModuleNameW) return FALSE; - if (!NT_SUCCESS(Status)) - { - SetLastErrorByStatus(Status); - return FALSE; - } - - lpModuleNameW = pTeb->StaticUnicodeString.Buffer; + /* Call the extended version of the API */ + Status = BasepGetModuleHandleExW(FALSE, + dwFlags, + lpModuleNameW->Buffer, + phModule); } - Ret = GetModuleHandleExW(dwFlags, - lpModuleNameW, - phModule); + /* If result was successful - return true */ + if (NT_SUCCESS(Status)) + Ret = TRUE; + /* Return result */ return Ret; } diff --git a/dll/win32/kernel32/process/procsup.c b/dll/win32/kernel32/process/procsup.c index 33b053d9324..39f700714d3 100644 --- a/dll/win32/kernel32/process/procsup.c +++ b/dll/win32/kernel32/process/procsup.c @@ -14,6 +14,10 @@ #define NDEBUG #include +UNICODE_STRING BasePathVariableName = RTL_CONSTANT_STRING(L"PATH"); +UNICODE_STRING BaseDefaultPath; +PLDR_DATA_TABLE_ENTRY BasepExeLdrEntry; + #define CMD_STRING L"cmd /c " extern __declspec(noreturn) @@ -352,13 +356,230 @@ BasepDuplicateAndWriteHandle(IN HANDLE ProcessHandle, } } +VOID +NTAPI +BasepLocateExeLdrEntry(IN PLDR_DATA_TABLE_ENTRY Entry, + IN PVOID Context, + OUT BOOLEAN *StopEnumeration) +{ + /* Make sure we get Entry, Context and valid StopEnumeration pointer */ + ASSERT(Entry); + ASSERT(Context); + ASSERT(StopEnumeration); + + /* If entry is already found - signal to stop */ + if (BasepExeLdrEntry) + { + /* Signal to stop enumeration and return */ + *StopEnumeration = TRUE; + return; + } + + /* We don't have a exe ldr entry, so try to see if this one is ours + by matching base address */ + if (Entry->DllBase == Context) + { + /* It matches, so remember the ldr entry */ + BasepExeLdrEntry = Entry; + + /* And stop enumeration */ + *StopEnumeration = TRUE; + } +} + +LPWSTR +WINAPI +BasepGetProcessPath(DWORD Reserved, + LPWSTR FullPath, + PVOID Environment) +{ + NTSTATUS Status; + LPWSTR AllocatedPath = NULL, ch; + ULONG DefaultLength = BaseDefaultPath.Length; + ULONG AppLength = 0; + UNICODE_STRING EnvPath; + LPWSTR NamePtr; + LPWSTR PathBuffer; + BOOLEAN SecondAttempt = FALSE; + PPEB Peb = NtCurrentPeb(); + + if (!Environment) RtlAcquirePebLock(); + + /* Query PATH env var into append path */ + Status = RtlQueryEnvironmentVariable_U(Environment, + &BasePathVariableName, + &BaseDefaultPathAppend); + if (NT_SUCCESS(Status)) + { + /* Add up PATH environment length */ + DefaultLength += BaseDefaultPathAppend.Length; + } + else if (Status == STATUS_BUFFER_TOO_SMALL) + { + /* We have to allocate path dynamically */ + AllocatedPath = RtlAllocateHeap(RtlGetProcessHeap(), 0, BaseDefaultPathAppend.Length + sizeof(UNICODE_NULL)); + + if (AllocatedPath) + { + /* Set up EnvPath */ + EnvPath.Buffer = AllocatedPath; + EnvPath.Length = BaseDefaultPathAppend.Length + sizeof(UNICODE_NULL); + EnvPath.MaximumLength = EnvPath.Length; + + /* Query PATH env var into newly allocated path */ + Status = RtlQueryEnvironmentVariable_U(Environment, + &BasePathVariableName, + &EnvPath); + + if (NT_SUCCESS(Status)) + { + DefaultLength += EnvPath.Length; + } + else + { + /* Free newly allocated path, it didn't work */ + RtlFreeHeap(RtlGetProcessHeap(), 0, AllocatedPath); + AllocatedPath = NULL; + Status = STATUS_NO_MEMORY; + } + } + } + +secondattempt: + if (!FullPath) + { + /* Initialize BasepExeLdrEntry if necessary */ + if (!BasepExeLdrEntry) + LdrEnumerateLoadedModules(0, BasepLocateExeLdrEntry, Peb->ImageBaseAddress); + + DPRINT("Found BasepExeLdrEntry %wZ\n", &BasepExeLdrEntry->FullDllName); + + /* Set name pointer to the full dll path */ + NamePtr = BasepExeLdrEntry->FullDllName.Buffer; + } + else + { + /* Set name pointer to the provided path */ + NamePtr = FullPath; + } + + /* Determine application path length */ + if (NamePtr) + { + ch = NamePtr; + while (*ch) + { + /* Check if there is a slash */ + if (*ch == L'\\') + { + /* Update app length */ + AppLength = (ULONG_PTR)ch - (ULONG_PTR)NamePtr + sizeof(WCHAR); + } + + ch++; + } + } + + /* Now check, if we found a valid path in the provided full path */ + if (!AppLength && FullPath && !SecondAttempt) + { + /* We were provided with a bad full path, retry again using just this app's path */ + FullPath = NULL; + SecondAttempt = TRUE; + goto secondattempt; + } + + /* Allocate the path buffer */ + PathBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, DefaultLength + AppLength + 2*sizeof(WCHAR)); + if (!PathBuffer) + { + /* Fail */ + if (!Environment) RtlReleasePebLock(); + if (AllocatedPath) RtlFreeHeap(RtlGetProcessHeap(), 0, AllocatedPath); + return NULL; + } + + /* Copy contents there */ + if (AppLength) + { + /* Remove trailing slashes if it's not root dir */ + if (AppLength != 3*sizeof(WCHAR)) + AppLength -= sizeof(WCHAR); + + /* Copy contents */ + RtlMoveMemory(PathBuffer, NamePtr, AppLength); + } + + /* Release the lock */ + if (!Environment) RtlReleasePebLock(); + + /* Finish preparing the path string */ + NamePtr = &PathBuffer[AppLength / sizeof(WCHAR)]; + + /* Put a separating ";" if something was added */ + if (AppLength) + { + *NamePtr = L';'; + NamePtr++; + } + + if (AllocatedPath) + { + /* Dynamically allocated env path, copy from the static buffer, + concatenate with dynamic buffer and free it */ + RtlMoveMemory(NamePtr, BaseDefaultPath.Buffer, BaseDefaultPath.Length); + RtlMoveMemory(&NamePtr[BaseDefaultPath.Length / sizeof(WCHAR)], AllocatedPath, EnvPath.Length); + + /* Free it */ + RtlFreeHeap(RtlGetProcessHeap(), 0, AllocatedPath); + } + else + { + /* Static env path string, copy directly from BaseDefaultPath */ + RtlMoveMemory(NamePtr, BaseDefaultPath.Buffer, DefaultLength); + } + + /* Null terminate the string */ + NamePtr[DefaultLength / sizeof(WCHAR)] = 0; + + return PathBuffer; +} + LPWSTR WINAPI BasepGetDllPath(LPWSTR FullPath, PVOID Environment) { - /* FIXME: Not yet implemented */ - return NULL; +#if 0 + LPWSTR DllPath = NULL; + + /* Acquire DLL directory lock */ + RtlEnterCriticalSection(&BaseDllDirectoryLock); + + /* Check if we have a base dll directory */ + if (BaseDllDirectory.Buffer) + { + /* Then get process path */ + DllPath = BasepGetProcessPath(0, FullPath, Environment); + + /* Release DLL directory lock */ + RtlLeaveCriticalSection(&BaseDllDirectoryLock); + + /* Return dll path */ + return DllPath; + } + + /* Release DLL directory lock */ + RtlLeaveCriticalSection(&BaseDllDirectoryLock); + + /* There is no base DLL directory */ + UNIMPLEMENTED; + + /* Return dll path */ + return DllPath; +#else + return BasepGetProcessPath(0, FullPath, Environment); +#endif } VOID diff --git a/dll/win32/lsasrv/lsarpc.c b/dll/win32/lsasrv/lsarpc.c index 9055bf608e0..c4c94970121 100644 --- a/dll/win32/lsasrv/lsarpc.c +++ b/dll/win32/lsasrv/lsarpc.c @@ -554,7 +554,7 @@ NTSTATUS WINAPI LsarLookupNames( for (i = 0; i < Count; i++) { OutputSids[i].Use = SidTypeWellKnownGroup; - OutputSids[i].RelativeId = DOMAIN_ALIAS_RID_ADMINS; + OutputSids[i].RelativeId = DOMAIN_USER_RID_ADMIN; //DOMAIN_ALIAS_RID_ADMINS; OutputSids[i].DomainIndex = i; } @@ -1185,7 +1185,7 @@ NTSTATUS WINAPI LsarLookupNames2( DWORD Count, PRPC_UNICODE_STRING Names, PLSAPR_REFERENCED_DOMAIN_LIST *ReferencedDomains, - PLSAPR_TRANSLATED_SID_EX TranslatedSids, + PLSAPR_TRANSLATED_SIDS_EX TranslatedSids, LSAP_LOOKUP_LEVEL LookupLevel, DWORD *MappedCount, DWORD LookupOptions, @@ -1287,14 +1287,132 @@ NTSTATUS WINAPI LsarLookupNames3( DWORD Count, PRPC_UNICODE_STRING Names, PLSAPR_REFERENCED_DOMAIN_LIST *ReferencedDomains, - PLSAPR_TRANSLATED_SID_EX2 TranslatedSids, + PLSAPR_TRANSLATED_SIDS_EX2 TranslatedSids, LSAP_LOOKUP_LEVEL LookupLevel, DWORD *MappedCount, DWORD LookupOptions, DWORD ClientRevision) { - UNIMPLEMENTED; - return STATUS_NOT_IMPLEMENTED; + SID_IDENTIFIER_AUTHORITY IdentifierAuthority = {SECURITY_NT_AUTHORITY}; + static const UNICODE_STRING DomainName = RTL_CONSTANT_STRING(L"DOMAIN"); + PLSAPR_REFERENCED_DOMAIN_LIST DomainsBuffer = NULL; + PLSAPR_TRANSLATED_SID_EX2 SidsBuffer = NULL; + ULONG SidsBufferLength; + ULONG DomainSidLength; + ULONG AccountSidLength; + PSID DomainSid; + PSID AccountSid; + ULONG i; + NTSTATUS Status; + + TRACE("LsarLookupNames3(%p, %lu, %p, %p, %p, %d, %p, %lu, %lu)\n", + PolicyHandle, Count, Names, ReferencedDomains, TranslatedSids, + LookupLevel, MappedCount, LookupOptions, ClientRevision); + + if (Count == 0) + return STATUS_NONE_MAPPED; + + TranslatedSids->Entries = Count; + TranslatedSids->Sids = NULL; + *ReferencedDomains = NULL; + + SidsBufferLength = Count * sizeof(LSAPR_TRANSLATED_SID_EX2); + SidsBuffer = MIDL_user_allocate(SidsBufferLength); + if (SidsBuffer == NULL) + return STATUS_INSUFFICIENT_RESOURCES; + + for (i = 0; i < Count; i++) + { + SidsBuffer[i].Use = SidTypeUser; + SidsBuffer[i].Sid = NULL; + SidsBuffer[i].DomainIndex = -1; + SidsBuffer[i].Flags = 0; + } + + DomainsBuffer = MIDL_user_allocate(sizeof(LSAPR_REFERENCED_DOMAIN_LIST)); + if (DomainsBuffer == NULL) + { + MIDL_user_free(SidsBuffer); + return STATUS_INSUFFICIENT_RESOURCES; + } + + DomainsBuffer->Entries = Count; + DomainsBuffer->Domains = MIDL_user_allocate(Count * sizeof(LSA_TRUST_INFORMATION)); + if (DomainsBuffer->Domains == NULL) + { + MIDL_user_free(DomainsBuffer); + MIDL_user_free(SidsBuffer); + return STATUS_INSUFFICIENT_RESOURCES; + } + + Status = RtlAllocateAndInitializeSid(&IdentifierAuthority, + 2, + SECURITY_BUILTIN_DOMAIN_RID, + DOMAIN_ALIAS_RID_ADMINS, + 0, 0, 0, 0, 0, 0, + &DomainSid); + if (!NT_SUCCESS(Status)) + { + MIDL_user_free(DomainsBuffer->Domains); + MIDL_user_free(DomainsBuffer); + MIDL_user_free(SidsBuffer); + return Status; + } + + DomainSidLength = RtlLengthSid(DomainSid); + + for (i = 0; i < Count; i++) + { + DomainsBuffer->Domains[i].Sid = MIDL_user_allocate(DomainSidLength); + RtlCopyMemory(DomainsBuffer->Domains[i].Sid, + DomainSid, + DomainSidLength); + + DomainsBuffer->Domains[i].Name.Buffer = MIDL_user_allocate(DomainName.MaximumLength); + DomainsBuffer->Domains[i].Name.Length = DomainName.Length; + DomainsBuffer->Domains[i].Name.MaximumLength = DomainName.MaximumLength; + RtlCopyMemory(DomainsBuffer->Domains[i].Name.Buffer, + DomainName.Buffer, + DomainName.MaximumLength); + } + + Status = RtlAllocateAndInitializeSid(&IdentifierAuthority, + 3, + SECURITY_BUILTIN_DOMAIN_RID, + DOMAIN_ALIAS_RID_ADMINS, + DOMAIN_USER_RID_ADMIN, + 0, 0, 0, 0, 0, + &AccountSid); + if (!NT_SUCCESS(Status)) + { + MIDL_user_free(DomainsBuffer->Domains); + MIDL_user_free(DomainsBuffer); + MIDL_user_free(SidsBuffer); + return Status; + } + + AccountSidLength = RtlLengthSid(AccountSid); + + for (i = 0; i < Count; i++) + { + SidsBuffer[i].Use = SidTypeWellKnownGroup; + SidsBuffer[i].Sid = MIDL_user_allocate(AccountSidLength); + + RtlCopyMemory(SidsBuffer[i].Sid, + AccountSid, + AccountSidLength); + + SidsBuffer[i].DomainIndex = i; + SidsBuffer[i].Flags = 0; + } + + *ReferencedDomains = DomainsBuffer; + *MappedCount = Count; + + TranslatedSids->Entries = Count; + TranslatedSids->Sids = SidsBuffer; + + return STATUS_SUCCESS; } @@ -1391,7 +1509,7 @@ NTSTATUS WINAPI LsarLookupNames4( DWORD Count, PRPC_UNICODE_STRING Names, PLSAPR_REFERENCED_DOMAIN_LIST *ReferencedDomains, - PLSAPR_TRANSLATED_SID_EX2 TranslatedSids, + PLSAPR_TRANSLATED_SIDS_EX2 TranslatedSids, LSAP_LOOKUP_LEVEL LookupLevel, DWORD *MappedCount, DWORD LookupOptions, diff --git a/dll/win32/shell32/lang/pl-PL.rc b/dll/win32/shell32/lang/pl-PL.rc index cb33116bd45..588990e6fe3 100644 --- a/dll/win32/shell32/lang/pl-PL.rc +++ b/dll/win32/shell32/lang/pl-PL.rc @@ -223,7 +223,7 @@ BEGIN LTEXT "", 14011, 68, 93, 160, 10 LTEXT "Utworzony:", 14014, 8, 118, 45, 10 LTEXT "", 14015, 68, 118, 160, 10 - AUTOCHECKBOX "&Tylko-do-odczytu", 14021, 45, 150, 67, 10 + AUTOCHECKBOX "&Tylko do odczytu", 14021, 45, 150, 67, 10 AUTOCHECKBOX "&Ukryty", 14022, 126, 150, 50, 10 END diff --git a/dll/win32/shell32/shlfileop.c b/dll/win32/shell32/shlfileop.c index 8fa50417493..f22b7225a00 100644 --- a/dll/win32/shell32/shlfileop.c +++ b/dll/win32/shell32/shlfileop.c @@ -584,7 +584,7 @@ BOOL QueueFile( FILE_OPERATION_CONTEXT * Context) { - FILE_ENTRY * from, *to; + FILE_ENTRY * from, *to = NULL; BOOL bRet = FALSE; if (Context->Index >= Context->from->dwNumFiles) @@ -593,7 +593,7 @@ QueueFile( /* get current file */ from = &Context->from->feFiles[Context->Index]; - if (Context->op->req->fFlags != FO_DELETE) + if (Context->op->req->wFunc != FO_DELETE) to = &Context->to->feFiles[Context->Index]; /* update status */ diff --git a/dll/win32/syssetup/wizard.c b/dll/win32/syssetup/wizard.c index 63d6bc2ed88..de46e556ad5 100644 --- a/dll/win32/syssetup/wizard.c +++ b/dll/win32/syssetup/wizard.c @@ -20,6 +20,7 @@ #include #define NTOS_MODE_USER #include +#include #include @@ -1916,11 +1917,30 @@ ProcessPageDlgProc(HWND hwndDlg, static VOID -SetupIsActive( DWORD dw ) +SetInstallationCompleted(VOID) { HKEY hKey = 0; - if (RegOpenKeyExW( HKEY_LOCAL_MACHINE, L"SYSTEM\\Setup", 0, KEY_WRITE, &hKey ) == ERROR_SUCCESS) { - RegSetValueExW( hKey, L"SystemSetupInProgress", 0, REG_DWORD, (CONST BYTE *)&dw, sizeof(dw) ); + DWORD InProgress = 0; + DWORD InstallDate; + + if (RegOpenKeyExW( HKEY_LOCAL_MACHINE, + L"SYSTEM\\Setup", + 0, + KEY_WRITE, + &hKey ) == ERROR_SUCCESS) + { + RegSetValueExW( hKey, L"SystemSetupInProgress", 0, REG_DWORD, (LPBYTE)&InProgress, sizeof(InProgress) ); + RegCloseKey( hKey ); + } + + if (RegOpenKeyExW( HKEY_LOCAL_MACHINE, + L"Software\\Microsoft\\Windows NT\\CurrentVersion", + 0, + KEY_WRITE, + &hKey ) == ERROR_SUCCESS) + { + InstallDate = (DWORD)time(NULL); + RegSetValueExW( hKey, L"InstallDate", 0, REG_DWORD, (LPBYTE)&InstallDate, sizeof(InstallDate) ); RegCloseKey( hKey ); } } @@ -1951,7 +1971,7 @@ FinishDlgProc(HWND hwndDlg, if (SetupData->UnattendSetup) { KillTimer(hwndDlg, 1); - SetupIsActive(0); + SetInstallationCompleted(); PostQuitMessage(0); } } @@ -1959,7 +1979,7 @@ FinishDlgProc(HWND hwndDlg, case WM_DESTROY: { - SetupIsActive(0); + SetInstallationCompleted(); PostQuitMessage(0); return TRUE; } diff --git a/dll/win32/user32/misc/display.c b/dll/win32/user32/misc/display.c index 196ff76d369..af430b3bbc1 100644 --- a/dll/win32/user32/misc/display.c +++ b/dll/win32/user32/misc/display.c @@ -116,6 +116,7 @@ EnumDisplayMonitors( HMONITOR *hMonitorList; LPRECT pRectList; HANDLE hHeap; + BOOL ret = FALSE; /* get list of monitors/rects */ iCount = NtUserEnumDisplayMonitors(hdc, lprcClip, NULL, NULL, 0); @@ -139,18 +140,15 @@ EnumDisplayMonitors( pRectList = HeapAlloc(hHeap, 0, sizeof (RECT) * iCount); if (pRectList == NULL) { - HeapFree(hHeap, 0, hMonitorList); SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return FALSE; + goto cleanup; } iCount = NtUserEnumDisplayMonitors(hdc, lprcClip, hMonitorList, pRectList, iCount); if (iCount <= 0) { /* FIXME: SetLastError() */ - HeapFree(hHeap, 0, hMonitorList); - HeapFree(hHeap, 0, pRectList); - return FALSE; + goto cleanup; } /* enumerate list */ @@ -167,11 +165,17 @@ EnumDisplayMonitors( } if (!lpfnEnum(hMonitor, hMonitorDC, pMonitorRect, dwData)) - break; + goto cleanup; /* return FALSE */ } - HeapFree(hHeap, 0, hMonitorList); - HeapFree(hHeap, 0, pRectList); - return TRUE; + + ret = TRUE; + +cleanup: + if(hMonitorList) + HeapFree(hHeap, 0, hMonitorList); + if(pRectList) + HeapFree(hHeap, 0, pRectList); + return ret; } diff --git a/dll/win32/user32/windows/class.c b/dll/win32/user32/windows/class.c index df665d1ce2d..0d9ae490b69 100644 --- a/dll/win32/user32/windows/class.c +++ b/dll/win32/user32/windows/class.c @@ -696,22 +696,20 @@ GetClassNameA( LPSTR lpClassName, int nMaxCount) { - ANSI_STRING ClassName; - int Result; - - ClassName.MaximumLength = nMaxCount; - ClassName.Buffer = lpClassName; - - Result = NtUserGetClassName(hWnd, - (PUNICODE_STRING)&ClassName, - TRUE); + WCHAR tmpbuf[MAX_ATOM_LEN + 1]; + int len; + + if (nMaxCount <= 0) return 0; + if (!GetClassNameW( hWnd, tmpbuf, sizeof(tmpbuf)/sizeof(WCHAR) )) return 0; + RtlUnicodeToMultiByteN( lpClassName, nMaxCount - 1, (PULONG)&len, tmpbuf, strlenW(tmpbuf) * sizeof(WCHAR) ); + lpClassName[len] = 0; TRACE("%p class/atom: %s/%04x %x\n", hWnd, IS_ATOM(lpClassName) ? NULL : lpClassName, IS_ATOM(lpClassName) ? lpClassName : 0, nMaxCount); - return Result; + return len; } @@ -732,8 +730,8 @@ GetClassNameW( ClassName.Buffer = lpClassName; Result = NtUserGetClassName(hWnd, - &ClassName, - FALSE); + FALSE, + &ClassName); TRACE("%p class/atom: %S/%04x %x\n", hWnd, IS_ATOM(lpClassName) ? NULL : lpClassName, @@ -914,8 +912,11 @@ RealGetWindowClassW( LPWSTR pszType, UINT cchType) { - /* FIXME: Implement correct functionality of RealGetWindowClass */ - return GetClassNameW(hwnd,pszType,cchType); + UNICODE_STRING ClassName; + ClassName.MaximumLength = cchType * sizeof(WCHAR); + ClassName.Buffer = (PWSTR)pszType; + + return NtUserGetClassName(hwnd,TRUE,&ClassName); } @@ -929,8 +930,14 @@ RealGetWindowClassA( LPSTR pszType, UINT cchType) { - /* FIXME: Implement correct functionality of RealGetWindowClass */ - return GetClassNameA(hwnd,pszType,cchType); + WCHAR tmpbuf[MAX_ATOM_LEN + 1]; + UINT len; + + if ((INT)cchType <= 0) return 0; + if (!RealGetWindowClassW( hwnd, tmpbuf, sizeof(tmpbuf)/sizeof(WCHAR) )) return 0; + RtlUnicodeToMultiByteN( pszType, cchType - 1, (PULONG)&len, tmpbuf, strlenW(tmpbuf) * sizeof(WCHAR) ); + pszType[len] = 0; + return len; } /* diff --git a/dll/win32/user32/windows/cursoricon.c b/dll/win32/user32/windows/cursoricon.c index 3da29262890..ce5a55fb456 100644 --- a/dll/win32/user32/windows/cursoricon.c +++ b/dll/win32/user32/windows/cursoricon.c @@ -458,16 +458,10 @@ static BOOL create_icon_bitmaps( const BITMAPINFO *bmi, int width, int height, void *color_bits, *mask_bits; BOOL ret = FALSE; HDC hdc = 0; - static HDC hScreenDC = 0; if (!(info = HeapAlloc( GetProcessHeap(), 0, max( size, FIELD_OFFSET( BITMAPINFO, bmiColors[2] ))))) return FALSE; - if(!hScreenDC) - { - hScreenDC = GetDC(0); - if(!hScreenDC) goto done; - } - if (!(hdc = CreateCompatibleDC(hScreenDC))) goto done; + if (!(hdc = CreateCompatibleDC(NULL))) goto done; memcpy( info, bmi, size ); info->bmiHeader.biHeight /= 2; @@ -491,8 +485,8 @@ static BOOL create_icon_bitmaps( const BITMAPINFO *bmi, int width, int height, else { if (!(*mask = CreateBitmap( width, height, 1, 1, NULL ))) goto done; - if (!(*color = CreateBitmap( width, height, GetDeviceCaps(hScreenDC, PLANES), - GetDeviceCaps(hScreenDC, BITSPIXEL), NULL ))) + if (!(*color = CreateBitmap( width, height, GetDeviceCaps(hdc, PLANES), + GetDeviceCaps(hdc, BITSPIXEL), NULL ))) { DeleteObject( *mask ); goto done; diff --git a/dll/win32/user32/windows/draw.c b/dll/win32/user32/windows/draw.c index dd50c75b1c3..5ecf9a53462 100644 --- a/dll/win32/user32/windows/draw.c +++ b/dll/win32/user32/windows/draw.c @@ -1564,20 +1564,29 @@ FlashWindow(HWND hWnd, BOOL bInvert) INT WINAPI FillRect(HDC hDC, CONST RECT *lprc, HBRUSH hbr) { - HBRUSH prevhbr; + BOOL Ret; + HBRUSH prevhbr = NULL; - if (hbr <= (HBRUSH)(COLOR_MENUBAR + 1)) + /* Select brush if specified */ + if (hbr) { - hbr = GetSysColorBrush(PtrToUlong(hbr) - 1); + /* Handle system colors */ + if (hbr <= (HBRUSH)(COLOR_MENUBAR + 1)) + hbr = GetSysColorBrush(PtrToUlong(hbr) - 1); + + prevhbr = SelectObject(hDC, hbr); + if (prevhbr == NULL) + return (INT)FALSE; } - if ((prevhbr = SelectObject(hDC, hbr)) == NULL) - { - return FALSE; - } - PatBlt(hDC, lprc->left, lprc->top, lprc->right - lprc->left, - lprc->bottom - lprc->top, PATCOPY); - SelectObject(hDC, prevhbr); - return TRUE; + + Ret = PatBlt(hDC, lprc->left, lprc->top, lprc->right - lprc->left, + lprc->bottom - lprc->top, PATCOPY); + + /* Select old brush */ + if (prevhbr) + SelectObject(hDC, prevhbr); + + return (INT)Ret; } /* diff --git a/dll/win32/user32/windows/input.c b/dll/win32/user32/windows/input.c index 63f266eb492..e9189576963 100644 --- a/dll/win32/user32/windows/input.c +++ b/dll/win32/user32/windows/input.c @@ -100,7 +100,6 @@ DragDetect( #endif } - /* * @implemented */ @@ -108,43 +107,9 @@ BOOL WINAPI EnableWindow(HWND hWnd, BOOL bEnable) { - // This will soon be moved to win32k. - BOOL Update; - LONG Style = GetWindowLongPtrW(hWnd, GWL_STYLE); - /* check if updating is needed */ - UINT bIsDisabled = (Style & WS_DISABLED); - Update = bIsDisabled; - - if (bEnable) - { - Style &= ~WS_DISABLED; - } - else - { - Update = !bIsDisabled; - - SendMessageW( hWnd, WM_CANCELMODE, 0, 0); - - /* Remove keyboard focus from that window if it had focus */ - if (hWnd == GetFocus()) - { - SetFocus(NULL); - } - Style |= WS_DISABLED; - } - - NtUserSetWindowLong(hWnd, GWL_STYLE, Style, FALSE); - - if (Update) - { - IntNotifyWinEvent(EVENT_OBJECT_STATECHANGE, hWnd, OBJID_WINDOW, CHILDID_SELF, 0); - SendMessageW(hWnd, WM_ENABLE, (LPARAM)bEnable, 0); - } - // Return nonzero if it was disabled, or zero if it wasn't: - return bIsDisabled; + return NtUserCallTwoParam((DWORD_PTR)hWnd, (DWORD_PTR)bEnable, TWOPARAM_ROUTINE_ENABLEWINDOW); } - /* * @implemented */ diff --git a/dll/win32/user32/windows/menu.c b/dll/win32/user32/windows/menu.c index 405e7809827..3408d73c3b4 100644 --- a/dll/win32/user32/windows/menu.c +++ b/dll/win32/user32/windows/menu.c @@ -1576,6 +1576,11 @@ static BOOL FASTCALL MenuShowPopup(HWND hwndOwner, HMENU hmenu, UINT id, UINT fl MenuInfo.FocusedItem = NO_SELECTED_ITEM; } + /* ReactOS Check */ + if (!ValidateHwnd(hwndOwner)) + { // This window maybe already DEAD!!! + return FALSE; + } /* store the owner for DrawItem */ MenuInfo.WndOwner = hwndOwner; MenuSetRosMenuInfo(&MenuInfo); @@ -3174,6 +3179,7 @@ static INT FASTCALL MenuTrackMenu(HMENU hmenu, UINT wFlags, INT x, INT y, BOOL fRemove; INT executedMenuId = -1; MTRACKER mt; + HWND capture_win; BOOL enterIdleSent = FALSE; mt.TrackFlags = 0; @@ -3207,12 +3213,16 @@ static INT FASTCALL MenuTrackMenu(HMENU hmenu, UINT wFlags, INT x, INT y, fEndMenu = !fRemove; } - SetCapture(mt.OwnerWnd); - (void)NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER, mt.OwnerWnd); + if (wFlags & TF_ENDMENU) fEndMenu = TRUE; + + /* owner may not be visible when tracking a popup, so use the menu itself */ + capture_win = (wFlags & TPM_POPUPMENU) ? MenuInfo.Wnd : mt.OwnerWnd; + (void)NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER, capture_win); // 1 + SetCapture(capture_win); // 2 - FIXME("MenuTrackMenu 1\n"); while (! fEndMenu) { + BOOL ErrorExit = FALSE; PVOID menu = ValidateHandle(mt.CurrentMenu, VALIDATE_TYPE_MENU); if (!menu) /* sometimes happens if I do a window manager close */ break; @@ -3230,6 +3240,12 @@ static INT FASTCALL MenuTrackMenu(HMENU hmenu, UINT wFlags, INT x, INT y, } else { + /* ReactOS Check */ + if (!ValidateHwnd(mt.OwnerWnd) || !ValidateHwnd(MenuInfo.Wnd)) + { + ErrorExit = TRUE; // Do not wait on dead windows, now test_capture_4 works. + break; + } if (!enterIdleSent) { HWND win = MenuInfo.Flags & MF_POPUP ? MenuInfo.Wnd : NULL; @@ -3238,9 +3254,10 @@ static INT FASTCALL MenuTrackMenu(HMENU hmenu, UINT wFlags, INT x, INT y, } WaitMessage(); } - //FIXME("MenuTrackMenu loop 1\n"); } + if (ErrorExit) break; // Gracefully dropout. + /* check if EndMenu() tried to cancel us, by posting this message */ if (msg.message == WM_CANCELMODE) { @@ -3446,7 +3463,6 @@ static INT FASTCALL MenuTrackMenu(HMENU hmenu, UINT wFlags, INT x, INT y, { PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE ); DispatchMessageW( &msg ); - //FIXME("MenuTrackMenu loop 2\n"); continue; } @@ -3457,9 +3473,7 @@ static INT FASTCALL MenuTrackMenu(HMENU hmenu, UINT wFlags, INT x, INT y, if (fRemove && !(mt.TrackFlags & TF_SKIPREMOVE) ) PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE ); else mt.TrackFlags &= ~TF_SKIPREMOVE; - //FIXME("MenuTrackMenu loop 3\n"); } - FIXME("MenuTrackMenu 2\n"); (void)NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER, NULL); SetCapture(NULL); /* release the capture */ @@ -3518,12 +3532,11 @@ static BOOL FASTCALL MenuInitTracking(HWND hWnd, HMENU hMenu, BOOL bPopup, UINT HideCaret(0); - MenuGetRosMenuInfo(&MenuInfo, hMenu); /* This makes the menus of applications built with Delphi work. * It also enables menus to be displayed in more than one window, * but there are some bugs left that need to be fixed in this case. */ - if(MenuInfo.Self == hMenu) + if (MenuGetRosMenuInfo(&MenuInfo, hMenu)) { MenuInfo.Wnd = hWnd; MenuSetRosMenuInfo(&MenuInfo); @@ -3655,13 +3668,7 @@ VOID MenuTrackKbdMenuBar(HWND hwnd, UINT wParam, WCHAR wChar) MenuSelectItem( hwnd, &MenuInfo, uItem, TRUE, 0 ); - if (wParam & HTSYSMENU) - { - /* prevent sysmenu activation for managed windows on Alt down/up */ -// if (GetPropA( hwnd, "__wine_x11_managed" )) - wFlags |= TF_ENDMENU; /* schedule end of menu tracking */ - } - else + if (!(wParam & HTSYSMENU) || wChar == ' ') { if( uItem == NO_SELECTED_ITEM ) MenuMoveSelection( hwnd, &MenuInfo, ITEM_NEXT ); @@ -3690,6 +3697,12 @@ BOOL WINAPI TrackPopupMenuEx( HMENU Menu, UINT Flags, int x, int y, return FALSE; } + /* ReactOS Check */ + if (!ValidateHwnd(Wnd)) + { + return FALSE; + } + MenuGetRosMenuInfo(&MenuInfo, Menu); if (IsWindow(MenuInfo.Wnd)) { diff --git a/dll/win32/user32/windows/message.c b/dll/win32/user32/windows/message.c index f00e6670a00..8cc1a07f581 100644 --- a/dll/win32/user32/windows/message.c +++ b/dll/win32/user32/windows/message.c @@ -2380,8 +2380,7 @@ GetCapture(VOID) BOOL WINAPI ReleaseCapture(VOID) { - NtUserSetCapture(NULL); - return(TRUE); + return (BOOL)NtUserCallNoParam(NOPARAM_ROUTINE_RELEASECAPTURE); } @@ -2491,11 +2490,13 @@ BOOL WINAPI SetMessageQueue(int cMessagesMax) } typedef DWORD (WINAPI * RealGetQueueStatusProc)(UINT flags); typedef DWORD (WINAPI * RealMsgWaitForMultipleObjectsExProc)(DWORD nCount, CONST HANDLE *lpHandles, DWORD dwMilliseconds, DWORD dwWakeMask, DWORD dwFlags); +typedef BOOL (WINAPI * RealInternalGetMessageProc)(LPMSG,HWND,UINT,UINT,UINT,BOOL); +typedef BOOL (WINAPI * RealWaitMessageExProc)(DWORD,UINT); typedef struct _USER_MESSAGE_PUMP_ADDRESSES { DWORD cbSize; - //NtUserRealInternalGetMessageProc NtUserRealInternalGetMessage; - //NtUserRealWaitMessageExProc NtUserRealWaitMessageEx; + RealInternalGetMessageProc NtUserRealInternalGetMessage; + RealWaitMessageExProc NtUserRealWaitMessageEx; RealGetQueueStatusProc RealGetQueueStatus; RealMsgWaitForMultipleObjectsExProc RealMsgWaitForMultipleObjectsEx; } USER_MESSAGE_PUMP_ADDRESSES, * PUSER_MESSAGE_PUMP_ADDRESSES; @@ -2515,8 +2516,8 @@ CRITICAL_SECTION gcsMPH; MESSAGEPUMPHOOKPROC gpfnInitMPH; DWORD gcLoadMPH = 0; USER_MESSAGE_PUMP_ADDRESSES gmph = {sizeof(USER_MESSAGE_PUMP_ADDRESSES), - //NtUserRealInternalGetMessage, - //NtUserRealInternalWaitMessageEx, + NtUserRealInternalGetMessage, + NtUserRealWaitMessageEx, RealGetQueueStatus, RealMsgWaitForMultipleObjectsEx }; @@ -2532,8 +2533,8 @@ BOOL WINAPI IsInsideMessagePumpHook() void WINAPI ResetMessagePumpHook(PUSER_MESSAGE_PUMP_ADDRESSES Addresses) { Addresses->cbSize = sizeof(USER_MESSAGE_PUMP_ADDRESSES); - //Addresses->NtUserRealInternalGetMessage = (NtUserRealInternalGetMessageProc)NtUserRealInternalGetMessage; - //Addresses->NtUserRealWaitMessageEx = (NtUserRealWaitMessageExProc)NtUserRealInternalWaitMessageEx; + Addresses->NtUserRealInternalGetMessage = NtUserRealInternalGetMessage; + Addresses->NtUserRealWaitMessageEx = NtUserRealWaitMessageEx; Addresses->RealGetQueueStatus = RealGetQueueStatus; Addresses->RealMsgWaitForMultipleObjectsEx = RealMsgWaitForMultipleObjectsEx; } diff --git a/dll/win32/user32/windows/paint.c b/dll/win32/user32/windows/paint.c index 433577eedf5..dff5f98afd3 100644 --- a/dll/win32/user32/windows/paint.c +++ b/dll/win32/user32/windows/paint.c @@ -107,19 +107,19 @@ GetUpdateRect( pWnd = ValidateHwnd(Wnd); if (!pWnd) return FALSE; -/* + if ( pWnd->hrgnUpdate || pWnd->state & (WNDS_SENDERASEBACKGROUND|WNDS_SENDNCPAINT|WNDS_UPDATEDIRTY|WNDS_PAINTNOTPROCESSED)) - {*/ + { return NtUserGetUpdateRect(Wnd, Rect, Erase); -/* } + } if (Rect) { // Did the Rgn update? No! Back set and shutup! Rect->left = Rect->right = Rect->top = Rect->bottom = 0; } return FALSE; // msdn: "If there is no update region, the return value is zero." -*/ + } @@ -144,14 +144,14 @@ GetUpdateRgn( pWnd = ValidateHwnd(hWnd); if (!pWnd) return ERROR; -/* + if ( pWnd->hrgnUpdate || pWnd->state & (WNDS_SENDERASEBACKGROUND|WNDS_SENDNCPAINT|WNDS_UPDATEDIRTY|WNDS_PAINTNOTPROCESSED)) - {*/ + { return NtUserGetUpdateRgn(hWnd, hRgn, bErase); -/* } + } SetRectRgn(hRgn, 0, 0, 0, 0); - return NULLREGION;*/ + return NULLREGION; } @@ -239,14 +239,14 @@ UpdateWindow( if (!pWnd) return FALSE; -/* + if ( pWnd->hrgnUpdate || pWnd->state & WNDS_INTERNALPAINT || pWnd->spwndChild ) - {*/ + { return NtUserCallHwndLock(hWnd, HWNDLOCK_ROUTINE_UPDATEWINDOW); -/* } - return TRUE;*/ + } + return TRUE; } /* @@ -286,7 +286,7 @@ GetWindowRgn( if (!Ret) return ERROR; - if (pWnd->fnid != FNID_DESKTOP) + if (hWnd != GetDesktopWindow()) // pWnd->fnid != FNID_DESKTOP) Ret = OffsetRgn(hRgn, -pWnd->rcWindow.left, -pWnd->rcWindow.top); if (pWnd->ExStyle & WS_EX_LAYOUTRTL) @@ -320,7 +320,7 @@ GetWindowRgnBox( if (!Ret) return ERROR; - if (pWnd->fnid != FNID_DESKTOP) + if (hWnd != GetDesktopWindow()) // pWnd->fnid != FNID_DESKTOP) OffsetRect(lprc, -pWnd->rcWindow.left, -pWnd->rcWindow.top); if (pWnd->ExStyle & WS_EX_LAYOUTRTL) diff --git a/include/ndk/ldrfuncs.h b/include/ndk/ldrfuncs.h index 743d213b87e..1bf8a83d32c 100644 --- a/include/ndk/ldrfuncs.h +++ b/include/ndk/ldrfuncs.h @@ -118,4 +118,12 @@ LdrProcessRelocationBlockLongLong( IN LONGLONG Delta ); +NTSTATUS +NTAPI +LdrEnumerateLoadedModules( + IN BOOLEAN ReservedFlag, + IN PLDR_ENUM_CALLBACK EnumProc, + IN PVOID Context +); + #endif diff --git a/include/ndk/ldrtypes.h b/include/ndk/ldrtypes.h index d706fec93e3..8887a040b07 100644 --- a/include/ndk/ldrtypes.h +++ b/include/ndk/ldrtypes.h @@ -71,14 +71,25 @@ Author: // // LdrLockLoaderLock Flags // -#define LDR_LOCK_LOADER_LOCK_FLAG_RAISE_STATUS 0x00000001 -#define LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY 0x00000002 +#define LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS 0x00000001 +#define LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY 0x00000002 + +#define LDR_LOCK_LOADER_LOCK_DISPOSITION_INVALID 0 +#define LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED 1 +#define LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_NOT_ACQUIRED 2 // // FIXME: THIS SHOULD *NOT* BE USED! // #define IMAGE_SCN_TYPE_NOLOAD 0x00000002 +// +// Loader datafile/imagemapping macros +// +#define LDR_IS_DATAFILE(handle) (((ULONG_PTR)(handle)) & (ULONG_PTR)1) +#define LDR_IS_IMAGEMAPPING(handle) (((ULONG_PTR)(handle)) & (ULONG_PTR)2) +#define LDR_IS_RESOURCE(handle) (LDR_IS_IMAGEMAPPING(handle) || LDR_IS_DATAFILE(handle)) + // // Loader Data stored in the PEB // @@ -188,4 +199,10 @@ typedef struct _ALT_RESOURCE_MODULE #endif } ALT_RESOURCE_MODULE, *PALT_RESOURCE_MODULE; +// +// Callback function for LdrEnumerateLoadedModules +// +typedef VOID (NTAPI LDR_ENUM_CALLBACK)(IN PLDR_DATA_TABLE_ENTRY ModuleInformation, IN PVOID Parameter, OUT BOOLEAN *Stop); +typedef LDR_ENUM_CALLBACK *PLDR_ENUM_CALLBACK; + #endif diff --git a/include/ndk/rtltypes.h b/include/ndk/rtltypes.h index c211ccada3c..3b932372ca9 100644 --- a/include/ndk/rtltypes.h +++ b/include/ndk/rtltypes.h @@ -1012,7 +1012,7 @@ typedef struct _CURDIR HANDLE Handle; } CURDIR, *PCURDIR; -typedef struct RTL_DRIVE_LETTER_CURDIR +typedef struct _RTL_DRIVE_LETTER_CURDIR { USHORT Flags; USHORT Length; @@ -1020,6 +1020,13 @@ typedef struct RTL_DRIVE_LETTER_CURDIR UNICODE_STRING DosPath; } RTL_DRIVE_LETTER_CURDIR, *PRTL_DRIVE_LETTER_CURDIR; +typedef struct _RTL_PERTHREAD_CURDIR +{ + PRTL_DRIVE_LETTER_CURDIR CurrentDirectories; + PUNICODE_STRING ImageName; + PVOID Environment; +} RTL_PERTHREAD_CURDIR, *PRTL_PERTHREAD_CURDIR; + // // Private State structure for RtlAcquirePrivilege/RtlReleasePrivilege // diff --git a/include/psdk/iphlpapi.h b/include/psdk/iphlpapi.h index 56c32fdc087..a799280d265 100644 --- a/include/psdk/iphlpapi.h +++ b/include/psdk/iphlpapi.h @@ -19,6 +19,9 @@ DWORD WINAPI DeleteProxyArpEntry(DWORD,DWORD,DWORD); DWORD WINAPI EnableRouter(HANDLE*,OVERLAPPED*); DWORD WINAPI FlushIpNetTable(DWORD); DWORD WINAPI GetAdapterIndex(LPWSTR,PULONG); +#ifdef _WINSOCK2API_ +DWORD WINAPI GetAdaptersAddresses(ULONG,ULONG,PVOID,PIP_ADAPTER_ADDRESSES,PULONG); +#endif DWORD WINAPI GetAdaptersInfo(PIP_ADAPTER_INFO,PULONG); DWORD WINAPI GetBestInterface(IPAddr,PDWORD); DWORD WINAPI GetBestRoute(DWORD,DWORD,PMIB_IPFORWARDROW); diff --git a/include/psdk/ksmedia.h b/include/psdk/ksmedia.h index 4873e1dbe64..3860e73b33f 100644 --- a/include/psdk/ksmedia.h +++ b/include/psdk/ksmedia.h @@ -348,6 +348,25 @@ typedef struct { WAVEFORMATEX WaveFormatEx; } KSDATAFORMAT_WAVEFORMATEX, *PKSDATAFORMAT_WAVEFORMATEX; +#ifndef _WAVEFORMATEXTENSIBLE_ +#define _WAVEFORMATEXTENSIBLE_ +typedef struct { + WAVEFORMATEX Format; + union + { + WORD wValidBitsPerSample; + WORD wSamplesPerBlock; + WORD wReserved; + }Samples; + DWORD dwChannelMask; + GUID SubFormat; +} WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE; +#endif + +#if !defined(WAVE_FORMAT_EXTENSIBLE) +#define WAVE_FORMAT_EXTENSIBLE 0xFFFE +#endif + typedef struct { ULONG Flags; ULONG Control; @@ -734,4 +753,50 @@ typedef struct ULONG ChannelMask; } KSDATARANGE_MUSIC, *PKSDATARANGE_MUSIC; +#ifndef _SPEAKER_POSITIONS_ +#define _SPEAKER_POSITIONS_ + + +#define SPEAKER_FRONT_LEFT 0x1 +#define SPEAKER_FRONT_RIGHT 0x2 +#define SPEAKER_FRONT_CENTER 0x4 +#define SPEAKER_LOW_FREQUENCY 0x8 +#define SPEAKER_BACK_LEFT 0x10 +#define SPEAKER_BACK_RIGHT 0x20 +#define SPEAKER_FRONT_LEFT_OF_CENTER 0x40 +#define SPEAKER_FRONT_RIGHT_OF_CENTER 0x80 +#define SPEAKER_BACK_CENTER 0x100 +#define SPEAKER_SIDE_LEFT 0x200 +#define SPEAKER_SIDE_RIGHT 0x400 +#define SPEAKER_TOP_CENTER 0x800 +#define SPEAKER_TOP_FRONT_LEFT 0x1000 +#define SPEAKER_TOP_FRONT_CENTER 0x2000 +#define SPEAKER_TOP_FRONT_RIGHT 0x4000 +#define SPEAKER_TOP_BACK_LEFT 0x8000 +#define SPEAKER_TOP_BACK_CENTER 0x10000 +#define SPEAKER_TOP_BACK_RIGHT 0x20000 + +#define SPEAKER_RESERVED 0x7FFC0000 +#define SPEAKER_ALL 0x80000000 + +#endif + +#if (NTDDI_VERSION >= NTDDI_WINXP) +#define KSAUDIO_SPEAKER_DIRECTOUT 0 +#endif + +#define KSAUDIO_SPEAKER_MONO (SPEAKER_FRONT_CENTER) +#define KSAUDIO_SPEAKER_STEREO (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT) +#define KSAUDIO_SPEAKER_QUAD (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | \ + SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT) +#define KSAUDIO_SPEAKER_SURROUND (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | \ + SPEAKER_FRONT_CENTER | SPEAKER_BACK_CENTER) +#define KSAUDIO_SPEAKER_5POINT1 (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | \ + SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | \ + SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT) +#define KSAUDIO_SPEAKER_7POINT1 (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | \ + SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | \ + SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | \ + SPEAKER_FRONT_LEFT_OF_CENTER | SPEAKER_FRONT_RIGHT_OF_CENTER) + #endif diff --git a/include/psdk/winbase.h b/include/psdk/winbase.h index d011f3983dd..9049f50d2a2 100644 --- a/include/psdk/winbase.h +++ b/include/psdk/winbase.h @@ -2416,6 +2416,9 @@ typedef PCACTCTXW PCACTCTX; #define GetCommandLine GetCommandLineW #define GetCompressedFileSize GetCompressedFileSizeW #define GetComputerName GetComputerNameW +#if (_WIN32_WINNT >= 0x0500) +#define GetComputerNameEx GetComputerNameExW +#endif #define GetCurrentDirectory GetCurrentDirectoryW #define GetDefaultCommConfig GetDefaultCommConfigW #define GetDiskFreeSpace GetDiskFreeSpaceW @@ -2619,6 +2622,9 @@ typedef ENUMRESTYPEPROCA ENUMRESTYPEPROC; #define GetBinaryType GetBinaryTypeA #define GetCommandLine GetCommandLineA #define GetComputerName GetComputerNameA +#if (_WIN32_WINNT >= 0x0500) +#define GetComputerNameEx GetComputerNameExA +#endif #define GetCompressedFileSize GetCompressedFileSizeA #define GetCurrentDirectory GetCurrentDirectoryA #define GetDefaultCommConfig GetDefaultCommConfigA diff --git a/include/reactos/idl/lsa.idl b/include/reactos/idl/lsa.idl index 00949cf4779..2a9aba6e8cb 100644 --- a/include/reactos/idl/lsa.idl +++ b/include/reactos/idl/lsa.idl @@ -975,7 +975,7 @@ cpp_quote("#if _WIN32_WINNT >= 0x0500") [in] DWORD Count, [in, size_is(Count)] PRPC_UNICODE_STRING Names, [out] PLSAPR_REFERENCED_DOMAIN_LIST *ReferencedDomains, - [in, out] PLSAPR_TRANSLATED_SID_EX TranslatedSids, + [in, out] PLSAPR_TRANSLATED_SIDS_EX TranslatedSids, [in] LSAP_LOOKUP_LEVEL LookupLevel, [in, out] DWORD *MappedCount, [in] DWORD LookupOptions, @@ -1029,7 +1029,7 @@ cpp_quote("#if _WIN32_WINNT >= 0x0501") [in] DWORD Count, [in, size_is(Count)] PRPC_UNICODE_STRING Names, [out] PLSAPR_REFERENCED_DOMAIN_LIST *ReferencedDomains, - [in, out] PLSAPR_TRANSLATED_SID_EX2 TranslatedSids, + [in, out] PLSAPR_TRANSLATED_SIDS_EX2 TranslatedSids, [in] LSAP_LOOKUP_LEVEL LookupLevel, [in, out] DWORD *MappedCount, [in] DWORD LookupOptions, @@ -1088,7 +1088,7 @@ cpp_quote("#if _WIN32_WINNT >= 0x0501") [in] DWORD Count, [in, size_is(Count)] PRPC_UNICODE_STRING Names, [out] PLSAPR_REFERENCED_DOMAIN_LIST *ReferencedDomains, - [in, out] PLSAPR_TRANSLATED_SID_EX2 TranslatedSids, + [in, out] PLSAPR_TRANSLATED_SIDS_EX2 TranslatedSids, [in] LSAP_LOOKUP_LEVEL LookupLevel, [in, out] DWORD *MappedCount, [in] DWORD LookupOptions, diff --git a/include/reactos/libs/fullfat/ff_config.h b/include/reactos/libs/fullfat/ff_config.h index f81c79ac7c9..09383e336af 100644 --- a/include/reactos/libs/fullfat/ff_config.h +++ b/include/reactos/libs/fullfat/ff_config.h @@ -34,97 +34,138 @@ Here you can change the configuration of FullFAT as appropriate to your platform. */ - //---------- ENDIANESS -#define FF_LITTLE_ENDIAN // Choosing the Byte-order of your system is important. -//#define FF_BIG_ENDIAN // You may be able to provide better Byte-order swapping routines to FullFAT. - // See ff_memory.c for more information. +#define FF_LITTLE_ENDIAN // Choosing the Byte-order of your system is important. +//#define FF_BIG_ENDIAN // You may be able to provide better Byte-order swapping routines to FullFAT. + // See ff_memory.c for more information. + //---------- LFN (Long File-name) SUPPORT -#define FF_LFN_SUPPORT // Comment this out if you don't want to worry about Patent Issues. - // FullFAT works great with LFNs and without. You choose, its your project! +#define FF_LFN_SUPPORT // Comment this out if you don't want to worry about Patent Issues. + // FullFAT works great with LFNs and without. You choose, its your project! -//---------- LEGAL LFNS -//#define FF_LEGAL_LFNS // Enabling this define causes FullFAT to not infringe on any of Microsoft's patents when making LFN names. - // To do this, it will only create LFNs and no shortnames. Microsofts patents are only relevent when mapping - // a shortname to a long name. This is the same way that Linux gets around the FAT legal issues: - // see http://lkml.org/lkml/2009/6/26/314 - // - // Enabling this may break compatibility with devices that cannot read LFN filenames. - // Enabling this option causes no compatibility issues when reading any media. - -//---------- TIME SUPPORT -#define FF_TIME_SUPPORT // Should FullFAT use time stamping. Only if you have provided the relevant time drivers in ff_time.c - // Note, by default ff_time.c is set-up for the Windows Demonstration. Please see ff_time.c to disable. - -//---------- FILE SPACE ALLOCATION PERFORMANCE - // Uncomment the prefered method. (Can only choose a single method). -#define FF_ALLOC_DEFAULT // Only allocate as much as is needed. (Provides good performance, without wasting space). -//#define FF_ALLOC_DOUBLE // Doubles the size of a file each time allocation is required. (When high-performance writing is required). - -//---------- Use Native STDIO.h -//#define FF_USE_NATIVE_STDIO // Makes FullFAT conform to values provided by your native STDIO.h file. - -//---------- FREE SPACE CALCULATION -//#define FF_MOUNT_FIND_FREE // Uncomment this option to check for Freespace on a volume mount. (Performance Penalty while mounting). - // If not done in the mount, it will be done on the first call to FF_GetFreeSize() function. - -//---------- PATH CACHE -#define FF_PATH_CACHE // Enables a simply Path Caching mechanism that increases performance of repeated operations - // within the same path. E.g. a copy \dir1\*.* \dir2\*.* command. - // This command requires FF_MAX_PATH number of bytes of memory. (Defined below, default 2600). +//#define FF_INCLUDE_SHORT_NAME // HT addition, in 'FF_DIRENT', beside FileName, ShortName will be filled as well + // Useful for debugging, but also some situations its useful to know both. +//---------- SHORTNAMES CAN USE THE CASE BITS +#define FF_SHORTNAME_CASE // Works for XP+ e.g. short.TXT or SHORT.txt. -#define FF_PATH_CACHE_DEPTH 2 // The Number of PATH's to Cache. +//---------- UNICODE SUPPORT +#define FF_UNICODE_SUPPORT // If this is defined, then all of FullFAT's API's will expect to receive UTF-16 formatted strings. + // FF_FindFirst() and FF_FindNext() will also return Filenames in UTF-16 format. + // NOTE: This option may cause FullFAT to not "Clean-compile" when using GCC. This is because + // pedantically GCC refuses to accept C99 library functions, unless the -std=c99 flag is used. + // To use UNICODE (UTF-16, or UTF-32 depending on the size of wchar_t) you must have a C99 compliant + // compiler and library. -//---------- DON'T USE MALLOC -//#define FF_NO_MALLOC +//#define FF_UNICODE_UTF8_SUPPORT // If this is defined, then all of FullFAT's API's will expect to receive UTF-8 formatted strings. + // FF_FindFirst() and FF_FindNext() will also return Filenames in UTF-8 format. -//---------- DON'T - - -//---------- Hash Table Support -//#define FF_HASH_TABLE_SUPPORT // Enable HASH to speed up file creation. -#ifdef FF_HASH_TABLE_SUPPORT -#define FF_HASH_FUNCTION CRC16 -//#define FF_HASH_FUNCTION CRC8 -#endif + // Note the 2 UNICODE options are mutually exclusive. Only one can be enabled. + // Ensure that dirents are big enough to hold the maximum UTF-8 sequence. //---------- FAT12 SUPPORT -#define FF_FAT12_SUPPORT // Enable FAT12 Suppport. You can reduce the code-size by commenting this out. - // If you don't need FAT12 support, why have it. FAT12 is more complex to process, - // therefore savings can be made by not having it. +#define FF_FAT12_SUPPORT // Enable FAT12 Suppport. You can reduce the code-size by commenting this out. + // If you don't need FAT12 support, why have it. FAT12 is more complex to process, + // therefore savings can be made by not having it. + + +//---------- TIME SUPPORT +#define FF_TIME_SUPPORT // Should FullFAT use time stamping. Only if you have provided the relevant time drivers in ff_time.c + // Note, by default ff_time.c is set-up for the Windows Demonstration. Please see ff_time.c to disable. + + +//---------- FILE SPACE ALLOCATION PERFORMANCE + // Uncomment the prefered method. (Can only choose a single method). +#define FF_ALLOC_DEFAULT // Only allocate as much as is needed. (Provides good performance, without wasting space). +//#define FF_ALLOC_DOUBLE // Doubles the size of a file each time allocation is required. (When high-performance writing is required). + + +//---------- Use Native STDIO.h +//#define FF_USE_NATIVE_STDIO // Makes FullFAT conform to values provided by your native STDIO.h file. + + +//---------- FREE SPACE CALCULATION +//#define FF_MOUNT_FIND_FREE // Uncomment this option to check for Freespace on a volume mount. (Performance Penalty while mounting). + // If not done in the mount, it will be done on the first call to FF_GetFreeSize() function. + + +//---------- FIND API WILD-CARD SUPPORT +#define FF_FINDAPI_ALLOW_WILDCARDS // Defined to enable Wild-cards in the API. Disabling this, makes the API consistent with 1.0.x series. + +#define FF_WILDCARD_CASE_INSENSITIVE // Alter the case insensitivity of the Wild-card checking behaviour. + + +//---------- PATH CACHE ---------- +#define FF_PATH_CACHE // Enables a simply Path Caching mechanism that increases performance of repeated operations + // within the same path. E.g. a copy \dir1\*.* \dir2\*.* command. + // This command requires FF_MAX_PATH number of bytes of memory. (Defined below, default 2600). + +#define FF_PATH_CACHE_DEPTH 5 // The Number of PATH's to Cache. (Memory Requirement ~= FF_PATH_CACHE_DEPTH * FF_MAX_PATH). + + +//---------- HASH CACHE // Speed up File-creation with a HASH table. Provides up to 20x performance boost. +//#define FF_HASH_CACHE // Enable HASH to speed up file creation. +#define FF_HASH_CACHE_DEPTH 10 // Number of Directories to be Hashed. (For CRC16 memory is 8KB * DEPTH) +#define FF_HASH_FUNCTION CRC16 // Choose a 16-bit hash. +//#define FF_HASH_FUNCTION CRC8 // Choose an 8-bit hash. + + +//---------- BLKDEV USES SEMAPHORE +#define FF_BLKDEV_USES_SEM // When defined, each call to fnReadBlocks and fnWriteBlocks will be done while semaphore is locked + // See also ff_safety.c + // (HT addition) - Thanks to Hein Tibosch + + +//---------- MALLOC + // These should map on to platform specific memory allocators. +#define FF_MALLOC(aSize) FF_Malloc(aSize) +#define FF_FREE(apPtr) FF_Free(apPtr) + + +//---------- IN-LINE FUNCTIONS +//---------- INLINE KeyWord // Define FF_INLINE as your compiler's inline keyword. This is placed before the type qualifier. +#define FF_INLINE static __forceinline // Keywords to inline functions (Windows) +//#define FF_INLINE static inline // Standard for GCC + +//---------- Inline Memory Independence Routines for better performance, but bigger codesize. +//#define FF_INLINE_MEMORY_ACCESS +//---------- Inline Block Calculation Routines for slightly better performance in critical sections. +//#define FF_INLINE_BLOCK_CALCULATIONS + //---------- 64-Bit Number Support -#define FF_64_NUM_SUPPORT // This helps to give information about the FreeSpace and VolumeSize of a partition or volume. - // If you cannot support 64-bit integers, then FullFAT still works, its just that the functions: - // FF_GetFreeSize() and FF_GetVolumeSize() don't make sense when reporting sizes > 4GB. +#define FF_64_NUM_SUPPORT // This helps to give information about the FreeSpace and VolumeSize of a partition or volume. + // If you cannot support 64-bit integers, then FullFAT still works, its just that the functions: + // FF_GetFreeSize() and FF_GetVolumeSize() don't make sense when reporting sizes > 4GB. -//---------- Driver Sleep Time // How long FullFAT should sleep the thread for in ms, if FF_ERR_DRIVER_BUSY is recieved. -#define FF_DRIVER_BUSY_SLEEP 20 -//---------- Debugging Features -#define FF_DEBUG // Enable the Error Code string functions. const FF_T_INT8 *FF_GetErrMessage( FF_T_SINT32 iErrorCode); - // Uncommenting this just stops FullFAT error strings being compiled. +//---------- Driver Sleep Time +#define FF_DRIVER_BUSY_SLEEP 20 // How long FullFAT should sleep the thread for in ms, if FF_ERR_DRIVER_BUSY is recieved. -//---------- Actively Determine if partition is FAT -#define FF_FAT_CHECK // This is experimental, so if FullFAT won't mount your volume, comment this out - // Also report the problem to james@worm.me.uk + +//---------- DEBUGGING FEATURES (HELPFUL ERROR MESSAGES) +#define FF_DEBUG // Enable the Error Code string functions. const FF_T_INT8 *FF_GetErrMessage( FF_T_SINT32 iErrorCode); + // Uncommenting this just stops FullFAT error strings being compiled. + // Further calls to FF_GetErrMessage() are safe, and simply returns a pointer to a NULL string. (""). + // This should be disabled to reduce code-size dramatically. //---------- AUTOMATIC SETTINGS DO NOT EDIT -- These configure your options from above, and check sanity! #ifdef FF_LFN_SUPPORT -#define FF_MAX_FILENAME 260 +#define FF_MAX_FILENAME (260) #else -#define FF_MAX_FILENAME 13 +#define FF_MAX_FILENAME (13) #endif #ifdef FF_USE_NATIVE_STDIO #ifdef MAX_PATH #define FF_MAX_PATH MAX_PATH +#elif PATH_MAX +#define FF_MAX_PATH PATH_MAX #else #define FF_MAX_PATH 2600 #endif @@ -144,6 +185,16 @@ #endif #endif +#ifdef FF_UNICODE_SUPPORT +#ifdef FF_UNICODE_UTF8_SUPPORT +#error FullFAT Invalid ff_config.h file: Must choose a single UNICODE support option. FF_UNICODE_SUPPORT for UTF-16, FF_UNICODE_UTF8_SUPPORT for UTF-8. +#endif +#endif + +#ifndef FF_FAT_CHECK // FF_FAT_CHECK is now forced. +#define FF_FAT_CHECK +#endif + #ifndef FF_LITTLE_ENDIAN #ifndef FF_BIG_ENDIAN #error FullFAT Invalid ff_config.h file: An ENDIANESS must be defined for your platform. See ff_config.h file. @@ -156,16 +207,18 @@ #endif #endif -#ifdef FF_HASH_TABLE_SUPPORT +#ifdef FF_HASH_CACHE #if FF_HASH_FUNCTION == CRC16 #define FF_HASH_TABLE_SIZE 8192 #elif FF_HASH_FUNCTION == CRC8 #define FF_HASH_TABLE_SIZE 32 #else -#error Invalid Hashing function selected. CRC16 or CRC8! +#error FullFAT Invalid ff_config.h file: Invalid Hashing function selected. CRC16 or CRC8! #endif #endif #endif + +//---------- END-OF-CONFIGURATION diff --git a/include/reactos/libs/fullfat/ff_crc.h b/include/reactos/libs/fullfat/ff_crc.h index 7349269d836..51b658dc1f3 100644 --- a/include/reactos/libs/fullfat/ff_crc.h +++ b/include/reactos/libs/fullfat/ff_crc.h @@ -44,6 +44,7 @@ FF_T_UINT8 FF_GetCRC8 (FF_T_UINT8 *pbyData, FF_T_UINT32 stLength); FF_T_UINT16 FF_GetCRC16 (FF_T_UINT8 *pbyData, FF_T_UINT32 stLength); +FF_T_UINT32 FF_GetCRC32 (FF_T_UINT8 *pbyData, FF_T_UINT32 stLength); #endif diff --git a/include/reactos/libs/fullfat/ff_dir.h b/include/reactos/libs/fullfat/ff_dir.h index 7415eac06e6..6c99b7279c5 100644 --- a/include/reactos/libs/fullfat/ff_dir.h +++ b/include/reactos/libs/fullfat/ff_dir.h @@ -43,7 +43,7 @@ #include "ff_ioman.h" #include "ff_blk.h" #include "ff_fat.h" -#include "fat.h" +#include "ff_fatdef.h" #include "ff_memory.h" #include "ff_time.h" #include "ff_hash.h" @@ -52,54 +52,118 @@ #include typedef struct { - FF_T_INT8 FileName[FF_MAX_FILENAME]; - FF_T_UINT8 Attrib; + FF_T_UINT32 ulChainLength; + FF_T_UINT32 ulDirCluster; + FF_T_UINT32 ulCurrentClusterLCN; + FF_T_UINT32 ulCurrentClusterNum; + FF_T_UINT32 ulCurrentEntry; + FF_BUFFER *pBuffer; +} FF_FETCH_CONTEXT; + +typedef struct { FF_T_UINT32 Filesize; FF_T_UINT32 ObjectCluster; - + + // Book Keeping + FF_T_UINT32 CurrentCluster; + FF_T_UINT32 AddrCurrentCluster; + FF_T_UINT32 DirCluster; + FF_T_UINT16 CurrentItem; + // End Book Keeping + #ifdef FF_TIME_SUPPORT FF_SYSTEMTIME CreateTime; ///< Date and Time Created. FF_SYSTEMTIME ModifiedTime; ///< Date and Time Modified. FF_SYSTEMTIME AccessedTime; ///< Date of Last Access. #endif - //---- Book Keeping for FF_Find Functions - FF_T_UINT16 CurrentItem; - FF_T_UINT32 DirCluster; - FF_T_UINT32 CurrentCluster; - FF_T_UINT32 AddrCurrentCluster; - //FF_T_UINT8 NumLFNs; +#ifdef FF_FINDAPI_ALLOW_WILDCARDS +#ifdef FF_UNICODE_SUPPORT + FF_T_WCHAR szWildCard[FF_MAX_FILENAME]; +#else + FF_T_INT8 szWildCard[FF_MAX_FILENAME]; +#endif +#endif + +#ifdef FF_UNICODE_SUPPORT + FF_T_WCHAR FileName[FF_MAX_FILENAME]; +#else + FF_T_INT8 FileName[FF_MAX_FILENAME]; +#endif + +#if defined(FF_LFN_SUPPORT) && defined(FF_INCLUDE_SHORT_NAME) + FF_T_INT8 ShortName[13]; +#endif + FF_T_UINT8 Attrib; + FF_FETCH_CONTEXT FetchContext; } FF_DIRENT; - FF_ERROR FF_GetEntry (FF_IOMAN *pIoman, FF_T_UINT16 nEntry, FF_T_UINT32 DirCluster, FF_DIRENT *pDirent); - FF_T_SINT8 FF_PutEntry (FF_IOMAN *pIoman, FF_T_UINT16 Entry, FF_T_UINT32 DirCluster, FF_DIRENT *pDirent); - FF_T_SINT8 FF_FindEntry (FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *Name, FF_DIRENT *pDirent, FF_T_BOOL LFNs); - FF_ERROR FF_FindFirst (FF_IOMAN *pIoman, FF_DIRENT *pDirent, const FF_T_INT8 *path); - FF_ERROR FF_FindNext (FF_IOMAN *pIoman, FF_DIRENT *pDirent); - void FF_PopulateShortDirent(FF_IOMAN *pIoman, FF_DIRENT *pDirent, FF_T_UINT8 *EntryBuffer); - FF_T_SINT8 FF_PopulateLongDirent(FF_IOMAN *pIoman, FF_DIRENT *pDirent, FF_T_UINT32 DirCluster, FF_T_UINT16 nEntry); - FF_T_SINT8 FF_FetchEntry (FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT16 nEntry, FF_T_UINT8 *buffer); - FF_T_SINT8 FF_PushEntry (FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT16 nEntry, FF_T_UINT8 *buffer); - FF_T_BOOL FF_isEndOfDir (FF_T_UINT8 *EntryBuffer); - FF_T_SINT8 FF_FindNextInDir(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_DIRENT *pDirent); - FF_T_UINT32 FF_FindEntryInDir(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *name, FF_T_UINT8 pa_Attrib, FF_DIRENT *pDirent); - FF_T_SINT8 FF_CreateShortName(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *ShortName, FF_T_INT8 *LongName); - -void FF_lockDIR (FF_IOMAN *pIoman); -void FF_unlockDIR (FF_IOMAN *pIoman); -FF_T_UINT32 FF_CreateFile(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *FileName, FF_DIRENT *pDirent); -FF_ERROR FF_MkDir(FF_IOMAN *pIoman, const FF_T_INT8 *Path); -FF_T_SINT8 FF_CreateDirent(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_DIRENT *pDirent); -FF_T_SINT8 FF_ExtendDirectory(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster); -FF_T_UINT32 FF_FindDir(FF_IOMAN *pIoman, const FF_T_INT8 *path, FF_T_UINT16 pathLen); -FF_T_BOOL FF_CheckDirentHash(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT32 nHash); -FF_T_BOOL FF_DirHashed(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster); -FF_ERROR FF_AddDirentHash(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT32 nHash); -void FF_SetDirHashed(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster); +// PUBLIC API +#ifdef FF_UNICODE_SUPPORT +FF_ERROR FF_FindFirst (FF_IOMAN *pIoman, FF_DIRENT *pDirent, const FF_T_WCHAR *path); +FF_ERROR FF_MkDir (FF_IOMAN *pIoman, const FF_T_WCHAR *Path); +#else +FF_ERROR FF_FindFirst (FF_IOMAN *pIoman, FF_DIRENT *pDirent, const FF_T_INT8 *path); +FF_ERROR FF_MkDir (FF_IOMAN *pIoman, const FF_T_INT8 *Path); +#endif -void FF_RmLFNs(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT16 DirEntry); +FF_ERROR FF_FindNext (FF_IOMAN *pIoman, FF_DIRENT *pDirent); + + +// INTERNAL API +FF_ERROR FF_GetEntry (FF_IOMAN *pIoman, FF_T_UINT16 nEntry, FF_T_UINT32 DirCluster, FF_DIRENT *pDirent); +FF_ERROR FF_PutEntry (FF_IOMAN *pIoman, FF_T_UINT16 Entry, FF_T_UINT32 DirCluster, FF_DIRENT *pDirent); +FF_T_SINT8 FF_FindEntry (FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *Name, FF_DIRENT *pDirent, FF_T_BOOL LFNs); + +void FF_PopulateShortDirent (FF_IOMAN *pIoman, FF_DIRENT *pDirent, FF_T_UINT8 *EntryBuffer); +FF_ERROR FF_PopulateLongDirent (FF_IOMAN *pIoman, FF_DIRENT *pDirent, FF_T_UINT16 nEntry, FF_FETCH_CONTEXT *pFetchContext); + +FF_ERROR FF_InitEntryFetch (FF_IOMAN *pIoman, FF_T_UINT32 ulDirCluster, FF_FETCH_CONTEXT *pContext); +FF_ERROR FF_FetchEntryWithContext (FF_IOMAN *pIoman, FF_T_UINT32 ulEntry, FF_FETCH_CONTEXT *pContext, FF_T_UINT8 *pEntryBuffer); +FF_ERROR FF_PushEntryWithContext (FF_IOMAN *pIoman, FF_T_UINT32 ulEntry, FF_FETCH_CONTEXT *pContext, FF_T_UINT8 *pEntryBuffer); +void FF_CleanupEntryFetch (FF_IOMAN *pIoman, FF_FETCH_CONTEXT *pContext); + +FF_T_SINT8 FF_PushEntry (FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT16 nEntry, FF_T_UINT8 *buffer, void *pParam); +FF_T_BOOL FF_isEndOfDir (FF_T_UINT8 *EntryBuffer); +FF_ERROR FF_FindNextInDir (FF_IOMAN *pIoman, FF_DIRENT *pDirent, FF_FETCH_CONTEXT *pFetchContext); + +#ifdef FF_UNICODE_SUPPORT +FF_T_UINT32 FF_FindEntryInDir (FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, const FF_T_WCHAR *name, FF_T_UINT8 pa_Attrib, FF_DIRENT *pDirent, FF_ERROR *pError); +FF_T_SINT8 FF_CreateShortName (FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_WCHAR *ShortName, FF_T_WCHAR *LongName); +#else +FF_T_UINT32 FF_FindEntryInDir (FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, const FF_T_INT8 *name, FF_T_UINT8 pa_Attrib, FF_DIRENT *pDirent, FF_ERROR *pError); +FF_T_SINT8 FF_CreateShortName (FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *ShortName, FF_T_INT8 *LongName); +#endif + + +void FF_lockDIR (FF_IOMAN *pIoman); +void FF_unlockDIR (FF_IOMAN *pIoman); + +#ifdef FF_UNICODE_SUPPORT +FF_T_UINT32 FF_CreateFile(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_WCHAR *FileName, FF_DIRENT *pDirent, FF_ERROR *pError); +#else +FF_T_UINT32 FF_CreateFile(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *FileName, FF_DIRENT *pDirent, FF_ERROR *pError); +#endif + +FF_ERROR FF_CreateDirent (FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_DIRENT *pDirent); +FF_ERROR FF_ExtendDirectory (FF_IOMAN *pIoman, FF_T_UINT32 DirCluster); + +#ifdef FF_UNICODE_SUPPORT +FF_T_UINT32 FF_FindDir (FF_IOMAN *pIoman, const FF_T_WCHAR *path, FF_T_UINT16 pathLen, FF_ERROR *pError); +#else +FF_T_UINT32 FF_FindDir (FF_IOMAN *pIoman, const FF_T_INT8 *path, FF_T_UINT16 pathLen, FF_ERROR *pError); +#endif + +#ifdef FF_HASH_CACHE +FF_T_BOOL FF_CheckDirentHash (FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT32 nHash); +FF_T_BOOL FF_DirHashed (FF_IOMAN *pIoman, FF_T_UINT32 DirCluster); +FF_ERROR FF_AddDirentHash (FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT32 nHash); +FF_ERROR FF_HashDir (FF_IOMAN *pIoman, FF_T_UINT32 ulDirCluster); +#endif + +FF_ERROR FF_RmLFNs(FF_IOMAN *pIoman, FF_T_UINT16 usDirEntry, FF_FETCH_CONTEXT *pContext); #endif diff --git a/include/reactos/libs/fullfat/ff_error.h b/include/reactos/libs/fullfat/ff_error.h index 8a48c8f1cce..c6b39dcd018 100644 --- a/include/reactos/libs/fullfat/ff_error.h +++ b/include/reactos/libs/fullfat/ff_error.h @@ -40,53 +40,111 @@ #include "ff_config.h" #include "ff_types.h" +/** + Error codes are 32-bit numbers, and consist of three items: + 8Bits 8bits 16bits + ........ ........ ........ ........ + [ModuleID][FunctionID][-- ERROR CODE --] + +**/ + +#define FF_GETERROR(x) (x & 0x0000FFFF) + +#define FF_MODULE_SHIFT 24 +#define FF_FUNCTION_SHIFT 16 + +//----- FullFAT Module Identifiers +#define FF_MODULE_IOMAN (1 << FF_MODULE_SHIFT) +#define FF_MODULE_DIR (2 << FF_MODULE_SHIFT) +#define FF_MODULE_FILE (3 << FF_MODULE_SHIFT) +#define FF_MODULE_FAT (4 << FF_MODULE_SHIFT) +#define FF_MODULE_CRC (5 << FF_MODULE_SHIFT) +#define FF_MODULE_FORMAT (6 << FF_MODULE_SHIFT) +#define FF_MODULE_HASH (7 << FF_MODULE_SHIFT) +#define FF_MODULE_MEMORY (8 << FF_MODULE_SHIFT) +#define FF_MODULE_STRING (9 << FF_MODULE_SHIFT) +#define FF_MODULE_UNICODE (10 << FF_MODULE_SHIFT) +#define FF_MODULE_SAFETY (11 << FF_MODULE_SHIFT) +#define FF_MODULE_TIME (12 << FF_MODULE_SHIFT) +#define FF_MODULE_DRIVER (13 << FF_MODULE_SHIFT) // We can mark underlying platform error codes with this. + +//----- FullFAT Function Identifiers (In Modular Order) +//----- FF_IOMAN - The FullFAT I/O Manager. +#define FF_CREATEIOMAN (1 << FF_FUNCTION_SHIFT) | FF_MODULE_IOMAN +#define FF_DESTROYIOMAN (2 << FF_FUNCTION_SHIFT) | FF_MODULE_IOMAN +#define FF_REGISTERBLKDEVICE (3 << FF_FUNCTION_SHIFT) | FF_MODULE_IOMAN +#define FF_UNREGISTERBLKDEVICE (4 << FF_FUNCTION_SHIFT) | FF_MODULE_IOMAN +#define FF_MOUNTPARTITION (5 << FF_FUNCTION_SHIFT) | FF_MODULE_IOMAN +#define FF_UNMOUNTPARTITION (6 << FF_FUNCTION_SHIFT) | FF_MODULE_IOMAN +#define FF_FLUSHCACHE (7 << FF_FUNCTION_SHIFT) | FF_MODULE_IOMAN +#define FF_GETPARTITIONBLOCKSIZE (8 << FF_FUNCTION_SHIFT) | FF_MODULE_IOMAN +#define FF_BLOCKREAD (9 << FF_FUNCTION_SHIFT) | FF_MODULE_IOMAN +#define FF_BLOCKWRITE (10 << FF_FUNCTION_SHIFT) | FF_MODULE_IOMAN + +//----- FF_DIR - The FullFAT directory handling routines. +// -- COMPLETE THESE ERROR CODES TOMORROW :P + + /* FullFAT defines different Error-Code spaces for each module. This ensures that all error codes remain unique, and their meaning can be quickly identified. */ // Global Error Codes -#define FF_ERR_NONE 0 ///< No Error -#define FF_ERR_NULL_POINTER -2 ///< pIoman was NULL. -#define FF_ERR_NOT_ENOUGH_MEMORY -3 ///< malloc() failed! - Could not allocate handle memory. -#define FF_ERR_DEVICE_DRIVER_FAILED -4 ///< The Block Device driver reported a FATAL error, cannot continue. +#define FF_ERR_NONE 0 ///< No Error +//#define FF_ERR_GENERIC 1 ///< BAD NEVER USE THIS! +#define FF_ERR_NULL_POINTER 2 ///< pIoman was NULL. +#define FF_ERR_NOT_ENOUGH_MEMORY 3 ///< malloc() failed! - Could not allocate handle memory. +#define FF_ERR_DEVICE_DRIVER_FAILED 4 ///< The Block Device driver reported a FATAL error, cannot continue. // IOMAN Error Codes -#define FF_ERR_IOMAN_BAD_BLKSIZE -11 ///< The provided blocksize was not a multiple of 512. -#define FF_ERR_IOMAN_BAD_MEMSIZE -12 ///< The memory size was not a multiple of the blocksize. -#define FF_ERR_IOMAN_DEV_ALREADY_REGD -13 ///< Device was already registered. Use FF_UnRegister() to re-use this IOMAN with another device. -#define FF_ERR_IOMAN_NO_MOUNTABLE_PARTITION -14 ///< A mountable partition could not be found on the device. -#define FF_ERR_IOMAN_INVALID_FORMAT -15 ///< The -#define FF_ERR_IOMAN_INVALID_PARTITION_NUM -16 ///< The partition number provided was out of range. -#define FF_ERR_IOMAN_NOT_FAT_FORMATTED -17 ///< The partition did not look like a FAT partition. -#define FF_ERR_IOMAN_DEV_INVALID_BLKSIZE -18 ///< IOMAN object BlkSize is not compatible with the blocksize of this device driver. -#define FF_ERR_IOMAN_PARTITION_MOUNTED -19 ///< Device is in use by an actively mounted partition. Unmount the partition first. -#define FF_ERR_IOMAN_ACTIVE_HANDLES -20 ///< The partition cannot be unmounted until all active file handles are closed. (There may also be active handles on the cache). +#define FF_ERR_IOMAN_BAD_BLKSIZE 11 ///< The provided blocksize was not a multiple of 512. +#define FF_ERR_IOMAN_BAD_MEMSIZE 12 ///< The memory size was not a multiple of the blocksize. +#define FF_ERR_IOMAN_DEV_ALREADY_REGD 13 ///< Device was already registered. Use FF_UnRegister() to re-use this IOMAN with another device. +#define FF_ERR_IOMAN_NO_MOUNTABLE_PARTITION 14 ///< A mountable partition could not be found on the device. +#define FF_ERR_IOMAN_INVALID_FORMAT 15 ///< The +#define FF_ERR_IOMAN_INVALID_PARTITION_NUM 16 ///< The partition number provided was out of range. +#define FF_ERR_IOMAN_NOT_FAT_FORMATTED 17 ///< The partition did not look like a FAT partition. +#define FF_ERR_IOMAN_DEV_INVALID_BLKSIZE 18 ///< IOMAN object BlkSize is not compatible with the blocksize of this device driver. +#define FF_ERR_IOMAN_PARTITION_MOUNTED 19 ///< Device is in use by an actively mounted partition. Unmount the partition first. +#define FF_ERR_IOMAN_ACTIVE_HANDLES 20 ///< The partition cannot be unmounted until all active file handles are closed. (There may also be active handles on the cache). +#define FF_ERR_IOMAN_GPT_HEADER_CORRUPT 21 ///< The GPT partition table appears to be corrupt, refusing to mount. +#define FF_ERR_IOMAN_NOT_ENOUGH_FREE_SPACE 22 +#define FF_ERR_IOMAN_OUT_OF_BOUNDS_READ 23 +#define FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE 24 -// File Error Codes -30 + -#define FF_ERR_FILE_ALREADY_OPEN -30 ///< File is in use. -#define FF_ERR_FILE_NOT_FOUND -31 ///< File was not found. -#define FF_ERR_FILE_OBJECT_IS_A_DIR -32 ///< Tried to FF_Open() a Directory. -#define FF_ERR_FILE_IS_READ_ONLY -33 ///< Tried to FF_Open() a file marked read only. -#define FF_ERR_FILE_INVALID_PATH -34 ///< The path of the file was not found. -#define FF_ERR_FILE_NOT_OPENED_IN_WRITE_MODE -35 -#define FF_ERR_FILE_NOT_OPENED_IN_READ_MODE -36 -#define FF_ERR_FILE_EXTEND_FAILED -37 ///< Could not extend the file. -#define FF_ERR_FILE_DESTINATION_EXISTS -38 -#define FF_ERR_FILE_SOURCE_NOT_FOUND -39 -#define FF_ERR_FILE_DIR_NOT_FOUND -40 -#define FF_ERR_FILE_COULD_NOT_CREATE_DIRENT -41 +// File Error Codes 30 + +#define FF_ERR_FILE_ALREADY_OPEN 30 ///< File is in use. +#define FF_ERR_FILE_NOT_FOUND 31 ///< File was not found. +#define FF_ERR_FILE_OBJECT_IS_A_DIR 32 ///< Tried to FF_Open() a Directory. +#define FF_ERR_FILE_IS_READ_ONLY 33 ///< Tried to FF_Open() a file marked read only. +#define FF_ERR_FILE_INVALID_PATH 34 ///< The path of the file was not found. +#define FF_ERR_FILE_NOT_OPENED_IN_WRITE_MODE 35 +#define FF_ERR_FILE_NOT_OPENED_IN_READ_MODE 36 +#define FF_ERR_FILE_EXTEND_FAILED 37 ///< Could not extend the file. +#define FF_ERR_FILE_DESTINATION_EXISTS 38 +#define FF_ERR_FILE_SOURCE_NOT_FOUND 39 +#define FF_ERR_FILE_DIR_NOT_FOUND 40 +#define FF_ERR_FILE_COULD_NOT_CREATE_DIRENT 41 -// Directory Error Codes -50 + -#define FF_ERR_DIR_OBJECT_EXISTS -50 ///< A file or folder of the same name already exists in the current directory. -#define FF_ERR_DIR_DIRECTORY_FULL -51 ///< No more items could be added to the directory. -#define FF_ERR_DIR_END_OF_DIR -52 /// -#define FF_ERR_DIR_NOT_EMPTY -53 ///< Cannot delete a directory that contains files or folders. -#define FF_ERR_DIR_INVALID_PATH -54 ///< Could not find the directory specified by the path. -#define FF_ERR_DIR_CANT_EXTEND_ROOT_DIR -55 ///< Can't extend the root dir. +// Directory Error Codes 50 + +#define FF_ERR_DIR_OBJECT_EXISTS 50 ///< A file or folder of the same name already exists in the current directory. +#define FF_ERR_DIR_DIRECTORY_FULL 51 ///< No more items could be added to the directory. +#define FF_ERR_DIR_END_OF_DIR 52 /// +#define FF_ERR_DIR_NOT_EMPTY 53 ///< Cannot delete a directory that contains files or folders. +#define FF_ERR_DIR_INVALID_PATH 54 ///< Could not find the directory specified by the path. +#define FF_ERR_DIR_CANT_EXTEND_ROOT_DIR 55 ///< Can't extend the root dir. +#define FF_ERR_DIR_EXTEND_FAILED 56 ///< Not enough space to extend the directory. +#define FF_ERR_DIR_NAME_TOO_LONG 57 ///< Name exceeds the number of allowed charachters for a filename. -// Fat Error Codes -70 + -#define FF_ERR_FAT_NO_FREE_CLUSTERS -70 ///< No more free space is available on the disk. +// Fat Error Codes 70 + +#define FF_ERR_FAT_NO_FREE_CLUSTERS 70 ///< No more free space is available on the disk. + +// UNICODE Error Codes 100 + +#define FF_ERR_UNICODE_INVALID_CODE 100 ///< An invalid Unicode charachter was provided! +#define FF_ERR_UNICODE_DEST_TOO_SMALL 101 ///< Not enough space in the UTF-16 buffer to encode the entire sequence as UTF-16. +#define FF_ERR_UNICODE_INVALID_SEQUENCE 102 ///< An invalid UTF-16 sequence was encountered. +#define FF_ERR_UNICODE_CONVERSION_EXCEEDED 103 ///< Filename exceeds MAX long-filename length when converted to UTF-16. #ifdef FF_DEBUG const FF_T_INT8 *FF_GetErrMessage(FF_ERROR iErrorCode); diff --git a/include/reactos/libs/fullfat/ff_fat.h b/include/reactos/libs/fullfat/ff_fat.h index 2e6ff6702b9..0ff784590ab 100644 --- a/include/reactos/libs/fullfat/ff_fat.h +++ b/include/reactos/libs/fullfat/ff_fat.h @@ -39,7 +39,7 @@ #define _FF_FAT_H_ #include "ff_config.h" -#include "fat.h" +#include "ff_fatdef.h" #include "ff_ioman.h" #include "ff_blk.h" #include "ff_types.h" @@ -52,24 +52,23 @@ FF_T_UINT32 FF_getRealLBA (FF_IOMAN *pIoman, FF_T_UINT32 LBA); FF_T_UINT32 FF_Cluster2LBA (FF_IOMAN *pIoman, FF_T_UINT32 Cluster); FF_T_UINT32 FF_LBA2Cluster (FF_IOMAN *pIoman, FF_T_UINT32 Address); - FF_T_SINT32 FF_getFatEntry (FF_IOMAN *pIoman, FF_T_UINT32 nCluster); + FF_T_UINT32 FF_getFatEntry (FF_IOMAN *pIoman, FF_T_UINT32 nCluster, FF_ERROR *pError); + FF_ERROR FF_putFatEntry (FF_IOMAN *pIoman, FF_T_UINT32 nCluster, FF_T_UINT32 Value); FF_T_BOOL FF_isEndOfChain (FF_IOMAN *pIoman, FF_T_UINT32 fatEntry); - FF_T_SINT8 FF_putFatEntry (FF_IOMAN *pIoman, FF_T_UINT32 nCluster, FF_T_UINT32 Value); - FF_T_UINT32 FF_FindFreeCluster (FF_IOMAN *pIoman); + FF_T_UINT32 FF_FindFreeCluster (FF_IOMAN *pIoman, FF_ERROR *pError); FF_T_UINT32 FF_ExtendClusterChain (FF_IOMAN *pIoman, FF_T_UINT32 StartCluster, FF_T_UINT32 Count); - FF_T_SINT8 FF_UnlinkClusterChain (FF_IOMAN *pIoman, FF_T_UINT32 StartCluster, FF_T_UINT16 Count); - FF_T_UINT32 FF_TraverseFAT (FF_IOMAN *pIoman, FF_T_UINT32 Start, FF_T_UINT32 Count); - FF_T_UINT32 FF_CreateClusterChain (FF_IOMAN *pIoman); - FF_T_UINT32 FF_GetChainLength (FF_IOMAN *pIoman, FF_T_UINT32 pa_nStartCluster, FF_T_UINT32 *piEndOfChain); - FF_T_UINT32 FF_FindEndOfChain (FF_IOMAN *pIoman, FF_T_UINT32 Start); - FF_T_SINT8 FF_ClearCluster (FF_IOMAN *pIoman, FF_T_UINT32 nCluster); + FF_ERROR FF_UnlinkClusterChain (FF_IOMAN *pIoman, FF_T_UINT32 StartCluster, FF_T_UINT16 Count); + FF_T_UINT32 FF_TraverseFAT (FF_IOMAN *pIoman, FF_T_UINT32 Start, FF_T_UINT32 Count, FF_ERROR *pError); + FF_T_UINT32 FF_CreateClusterChain (FF_IOMAN *pIoman, FF_ERROR *pError); + FF_T_UINT32 FF_GetChainLength (FF_IOMAN *pIoman, FF_T_UINT32 pa_nStartCluster, FF_T_UINT32 *piEndOfChain, FF_ERROR *pError); + FF_T_UINT32 FF_FindEndOfChain (FF_IOMAN *pIoman, FF_T_UINT32 Start, FF_ERROR *pError); + FF_ERROR FF_ClearCluster (FF_IOMAN *pIoman, FF_T_UINT32 nCluster); #ifdef FF_64_NUM_SUPPORT - FF_T_UINT64 FF_GetFreeSize (FF_IOMAN *pIoman); + FF_T_UINT64 FF_GetFreeSize (FF_IOMAN *pIoman, FF_ERROR *pError); #else - FF_T_UINT32 FF_GetFreeSize (FF_IOMAN *pIoman); + FF_T_UINT32 FF_GetFreeSize (FF_IOMAN *pIoman, FF_ERROR *pError); #endif - FF_T_UINT32 FF_FindFreeCluster (FF_IOMAN *pIoman); - FF_T_UINT32 FF_CountFreeClusters (FF_IOMAN *pIoman); + FF_T_UINT32 FF_CountFreeClusters (FF_IOMAN *pIoman, FF_ERROR *pError); // WARNING: If this protoype changes, it must be updated in ff_ioman.c also! void FF_lockFAT (FF_IOMAN *pIoman); void FF_unlockFAT (FF_IOMAN *pIoman); diff --git a/include/reactos/libs/fullfat/ff_fatdef.h b/include/reactos/libs/fullfat/ff_fatdef.h new file mode 100644 index 00000000000..8e86d138a6d --- /dev/null +++ b/include/reactos/libs/fullfat/ff_fatdef.h @@ -0,0 +1,105 @@ +/***************************************************************************** + * FullFAT - High Performance, Thread-Safe Embedded FAT File-System * + * Copyright (C) 2009 James Walmsley (james@worm.me.uk) * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + * * + * IMPORTANT NOTICE: * + * ================= * + * Alternative Licensing is available directly from the Copyright holder, * + * (James Walmsley). For more information consult LICENSING.TXT to obtain * + * a Commercial license. * + * * + * See RESTRICTIONS.TXT for extra restrictions on the use of FullFAT. * + * * + * Removing the above notice is illegal and will invalidate this license. * + ***************************************************************************** + * See http://worm.me.uk/fullfat for more information. * + * Or http://fullfat.googlecode.com/ for latest releases and the wiki. * + *****************************************************************************/ +#ifndef _FF_FATDEF_H_ +#define _FF_FATDEF_H_ + +/* + This file defines offsets to various data for the FAT specification. +*/ + +// MBR / PBR Offsets + +#define FF_FAT_BYTES_PER_SECTOR 0x00B +#define FF_FAT_SECTORS_PER_CLUS 0x00D +#define FF_FAT_RESERVED_SECTORS 0x00E +#define FF_FAT_NUMBER_OF_FATS 0x010 +#define FF_FAT_ROOT_ENTRY_COUNT 0x011 +#define FF_FAT_16_TOTAL_SECTORS 0x013 +#define FF_FAT_32_TOTAL_SECTORS 0x020 +#define FF_FAT_16_SECTORS_PER_FAT 0x016 +#define FF_FAT_32_SECTORS_PER_FAT 0x024 +#define FF_FAT_ROOT_DIR_CLUSTER 0x02C + +#define FF_FAT_16_VOL_LABEL 0x02B +#define FF_FAT_32_VOL_LABEL 0x047 + +#define FF_FAT_PTBL 0x1BE +#define FF_FAT_PTBL_LBA 0x008 +#define FF_FAT_PTBL_ACTIVE 0x000 +#define FF_FAT_PTBL_ID 0x004 + +#define FF_FAT_MBR_SIGNATURE 0x1FE + +#define FF_FAT_DELETED 0xE5 + +// Directory Entry Offsets +#define FF_FAT_DIRENT_SHORTNAME 0x000 +#define FF_FAT_DIRENT_ATTRIB 0x00B +#define FF_FAT_DIRENT_CREATE_TIME 0x00E ///< Creation Time. +#define FF_FAT_DIRENT_CREATE_DATE 0x010 ///< Creation Date. +#define FF_FAT_DIRENT_LASTACC_DATE 0x012 ///< Date of Last Access. +#define FF_FAT_DIRENT_CLUS_HIGH 0x014 +#define FF_FAT_DIRENT_LASTMOD_TIME 0x016 ///< Time of Last modification. +#define FF_FAT_DIRENT_LASTMOD_DATE 0x018 ///< Date of Last modification. +#define FF_FAT_DIRENT_CLUS_LOW 0x01A +#define FF_FAT_DIRENT_FILESIZE 0x01C +#define FF_FAT_LFN_ORD 0x000 +#define FF_FAT_LFN_NAME_1 0x001 +#define FF_FAT_LFN_CHECKSUM 0x00D +#define FF_FAT_LFN_NAME_2 0x00E +#define FF_FAT_LFN_NAME_3 0x01C + +// Dirent Attributes +#define FF_FAT_ATTR_READONLY 0x01 +#define FF_FAT_ATTR_HIDDEN 0x02 +#define FF_FAT_ATTR_SYSTEM 0x04 +#define FF_FAT_ATTR_VOLID 0x08 +#define FF_FAT_ATTR_DIR 0x10 +#define FF_FAT_ATTR_ARCHIVE 0x20 +#define FF_FAT_ATTR_LFN 0x0F + +/** + * -- Hein_Tibosch additions for mixed case in shortnames -- + * + * Specifically, bit 4 means lowercase extension and bit 3 lowercase basename, + * which allows for combinations such as "example.TXT" or "HELLO.txt" but not "Mixed.txt" + */ + +#define FF_FAT_CASE_OFFS 0x0C ///< After NT/XP : 2 case bits +#define FF_FAT_CASE_ATTR_BASE 0x08 +#define FF_FAT_CASE_ATTR_EXT 0x10 + +#if defined(FF_LFN_SUPPORT) && defined(FF_INCLUDE_SHORT_NAME) +#define FF_FAT_ATTR_IS_LFN 0x40 ///< artificial attribute, for debugging only +#endif + +#endif + diff --git a/include/reactos/libs/fullfat/ff_file.h b/include/reactos/libs/fullfat/ff_file.h index e74d4a6a6ed..ac5528e38c7 100644 --- a/include/reactos/libs/fullfat/ff_file.h +++ b/include/reactos/libs/fullfat/ff_file.h @@ -75,19 +75,29 @@ typedef struct _FF_FILE { //---------- PROTOTYPES // PUBLIC (Interfaces): -FF_FILE *FF_Open (FF_IOMAN *pIoman, const FF_T_INT8 *path, FF_T_UINT8 Mode, FF_ERROR *pError); +#ifdef FF_UNICODE_SUPPORT +FF_FILE *FF_Open(FF_IOMAN *pIoman, const FF_T_WCHAR *path, FF_T_UINT8 Mode, FF_ERROR *pError); +FF_T_BOOL FF_isDirEmpty (FF_IOMAN *pIoman, const FF_T_WCHAR *Path); +FF_ERROR FF_RmFile (FF_IOMAN *pIoman, const FF_T_WCHAR *path); +FF_ERROR FF_RmDir (FF_IOMAN *pIoman, const FF_T_WCHAR *path); +FF_ERROR FF_Move (FF_IOMAN *pIoman, const FF_T_WCHAR *szSourceFile, const FF_T_WCHAR *szDestinationFile); +#else +FF_FILE *FF_Open(FF_IOMAN *pIoman, const FF_T_INT8 *path, FF_T_UINT8 Mode, FF_ERROR *pError); +FF_T_BOOL FF_isDirEmpty (FF_IOMAN *pIoman, const FF_T_INT8 *Path); +FF_ERROR FF_RmFile (FF_IOMAN *pIoman, const FF_T_INT8 *path); +FF_ERROR FF_RmDir (FF_IOMAN *pIoman, const FF_T_INT8 *path); +FF_ERROR FF_Move (FF_IOMAN *pIoman, const FF_T_INT8 *szSourceFile, const FF_T_INT8 *szDestinationFile); +#endif FF_ERROR FF_Close (FF_FILE *pFile); FF_T_SINT32 FF_GetC (FF_FILE *pFile); +FF_T_SINT32 FF_GetLine (FF_FILE *pFile, FF_T_INT8 *szLine, FF_T_UINT32 ulLimit); FF_T_SINT32 FF_Read (FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, FF_T_UINT8 *buffer); FF_T_SINT32 FF_Write (FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, FF_T_UINT8 *buffer); FF_T_BOOL FF_isEOF (FF_FILE *pFile); FF_ERROR FF_Seek (FF_FILE *pFile, FF_T_SINT32 Offset, FF_T_INT8 Origin); FF_T_SINT32 FF_PutC (FF_FILE *pFile, FF_T_UINT8 Value); FF_T_UINT32 FF_Tell (FF_FILE *pFile); -FF_ERROR FF_RmFile (FF_IOMAN *pIoman, const FF_T_INT8 *path); -FF_ERROR FF_RmDir (FF_IOMAN *pIoman, const FF_T_INT8 *path); -FF_T_BOOL FF_isDirEmpty (FF_IOMAN *pIoman, const FF_T_INT8 *Path); -FF_ERROR FF_Move (FF_IOMAN *pIoman, const FF_T_INT8 *szSourceFile, const FF_T_INT8 *szDestinationFile); + FF_T_UINT8 FF_GetModeBits (FF_T_INT8 *Mode); // Private : diff --git a/include/reactos/libs/fullfat/ff_format.h b/include/reactos/libs/fullfat/ff_format.h new file mode 100644 index 00000000000..d7c53e58a9f --- /dev/null +++ b/include/reactos/libs/fullfat/ff_format.h @@ -0,0 +1,47 @@ +/***************************************************************************** + * FullFAT - High Performance, Thread-Safe Embedded FAT File-System * + * Copyright (C) 2009 James Walmsley (james@worm.me.uk) * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + * * + * IMPORTANT NOTICE: * + * ================= * + * Alternative Licensing is available directly from the Copyright holder, * + * (James Walmsley). For more information consult LICENSING.TXT to obtain * + * a Commercial license. * + * * + * See RESTRICTIONS.TXT for extra restrictions on the use of FullFAT. * + * * + * Removing the above notice is illegal and will invalidate this license. * + ***************************************************************************** + * See http://worm.me.uk/fullfat for more information. * + * Or http://fullfat.googlecode.com/ for latest releases and the wiki. * + *****************************************************************************/ + +/** + * @file ff_format.c + * @author James Walmsley + * @ingroup FORMAT + * + **/ + + +#ifndef _FF_FORMAT_H_ +#define _FF_FORMAT_H_ + + + + + +#endif diff --git a/include/reactos/libs/fullfat/ff_ioman.h b/include/reactos/libs/fullfat/ff_ioman.h index 187ffa347f9..92d62ebd85d 100644 --- a/include/reactos/libs/fullfat/ff_ioman.h +++ b/include/reactos/libs/fullfat/ff_ioman.h @@ -87,8 +87,8 @@ typedef FF_T_SINT32 (*FF_READ_BLOCKS) (FF_T_UINT8 *pBuffer, FF_T_UINT32 SectorAd * @brief Describes the block device driver interface to FullFAT. **/ typedef struct { - FF_WRITE_BLOCKS fnWriteBlocks; ///< Function Pointer, to write a block(s) from a block device. - FF_READ_BLOCKS fnReadBlocks; ///< Function Pointer, to read a block(s) from a block device. + FF_WRITE_BLOCKS fnpWriteBlocks; ///< Function Pointer, to write a block(s) from a block device. + FF_READ_BLOCKS fnpReadBlocks; ///< Function Pointer, to read a block(s) from a block device. FF_T_UINT16 devBlkSize; ///< Block size that the driver deals with. void *pParam; ///< Pointer to some parameters e.g. for a Low-Level Driver Handle } FF_BLK_DEVICE; @@ -100,24 +100,33 @@ typedef struct { **/ typedef struct { FF_T_UINT32 Sector; ///< The LBA of the Cached sector. - FF_T_UINT8 Mode; ///< Read or Write mode. + FF_T_UINT32 LRU; ///< For the Least Recently Used algorithm. FF_T_UINT16 NumHandles; ///< Number of objects using this buffer. FF_T_UINT16 Persistance; ///< For the persistance algorithm. - FF_T_UINT32 LRU; ///< For the Least Recently Used algorithm. + FF_T_UINT8 Mode; ///< Read or Write mode. FF_T_BOOL Modified; ///< If the sector was modified since read. FF_T_BOOL Valid; ///< Initially FALSE. FF_T_UINT8 *pBuffer; ///< Pointer to the cache block. } FF_BUFFER; typedef struct { +#ifdef FF_UNICODE_SUPPORT + FF_T_WCHAR Path[FF_MAX_PATH]; +#else FF_T_INT8 Path[FF_MAX_PATH]; - FF_T_UINT32 DirCluster; -#ifdef FF_HASH_TABLE_SUPPORT - FF_HASH_TABLE pHashTable; - FF_T_BOOL bHashed; #endif + FF_T_UINT32 DirCluster; } FF_PATHCACHE; +#ifdef FF_HASH_CACHE +typedef struct { + FF_T_UINT32 ulDirCluster; ///< The Starting Cluster of the dir that the hash represents. + FF_HASH_TABLE pHashTable; ///< Pointer to the Hash Table object. + FF_T_UINT32 ulNumHandles; ///< Number of active Handles using this hash table. + FF_T_UINT32 ulMisses; ///< Number of times this Hash Table was missed, (i.e. how redundant it is). +} FF_HASHCACHE; +#endif + /** * @private * @brief FullFAT identifies a partition with the following data. @@ -129,7 +138,7 @@ typedef struct { FF_T_UINT16 BlkSize; ///< Size of a Sector Block in bytes. FF_T_UINT8 BlkFactor; ///< Scale Factor for blocksizes above 512! //FF_T_INT8 Name[FF_MAX_PARTITION_NAME]; ///< Partition Identifier e.g. c: sd0: etc. - //FF_T_INT8 VolLabel[12]; ///< Volume Label of the partition. + FF_T_INT8 VolLabel[12]; ///< Volume Label of the partition. FF_T_UINT32 BeginLBA; ///< LBA start address of the partition. FF_T_UINT32 PartSize; ///< Size of Partition in number of sectors. FF_T_UINT32 FatBeginLBA; ///< LBA of the FAT tables. @@ -182,14 +191,21 @@ typedef struct { FF_BLK_DEVICE *pBlkDevice; ///< Pointer to a Block device description. FF_PARTITION *pPartition; ///< Pointer to a partition description. FF_BUFFER *pBuffers; ///< Pointer to the first buffer description. + void *pSemaphore; ///< Pointer to a Semaphore object. (For buffer description modifications only!). +#ifdef FF_BLKDEV_USES_SEM + void *pBlkDevSemaphore; ///< Semaphore to guarantee Atomic access to the underlying block device, if required. +#endif + void *FirstFile; ///< Pointer to the first File object. + FF_T_UINT8 *pCacheMem; ///< Pointer to a block of memory for the cache. FF_T_UINT32 LastReplaced; ///< Marks which sector was last replaced in the cache. FF_T_UINT16 BlkSize; ///< The Block size that IOMAN is configured to. - FF_T_UINT8 *pCacheMem; ///< Pointer to a block of memory for the cache. FF_T_UINT16 CacheSize; ///< Size of the cache in number of Sectors. + FF_T_UINT8 PreventFlush; ///< Flushing to disk only allowed when 0 FF_T_UINT8 MemAllocation; ///< Bit-Mask identifying allocated pointers. FF_T_UINT8 Locks; ///< Lock Flag for FAT & DIR Locking etc (This must be accessed via a semaphore). - void *pSemaphore; ///< Pointer to a Semaphore object. (For buffer description modifications only!). - void *FirstFile; ///< Pointer to the first File object. +#ifdef FF_HASH_CACHE + FF_HASHCACHE HashCache[FF_HASH_CACHE_DEPTH]; +#endif } FF_IOMAN; // Bit-Masks for Memory Allocation testing. @@ -219,6 +235,8 @@ FF_T_UINT32 FF_GetVolumeSize(FF_IOMAN *pIoman); #endif // PUBLIC (To FullFAT Only): +FF_T_SINT32 FF_BlockRead (FF_IOMAN *pIoman, FF_T_UINT32 ulSectorLBA, FF_T_UINT32 ulNumSectors, void *pBuffer); +FF_T_SINT32 FF_BlockWrite (FF_IOMAN *pIoman, FF_T_UINT32 ulSectorLBA, FF_T_UINT32 ulNumSectors, void *pBuffer); FF_ERROR FF_IncreaseFreeClusters (FF_IOMAN *pIoman, FF_T_UINT32 Count); FF_ERROR FF_DecreaseFreeClusters (FF_IOMAN *pIoman, FF_T_UINT32 Count); FF_BUFFER *FF_GetBuffer (FF_IOMAN *pIoman, FF_T_UINT32 Sector, FF_T_UINT8 Mode); diff --git a/include/reactos/libs/fullfat/ff_memory.h b/include/reactos/libs/fullfat/ff_memory.h index 1d4507c4a85..5064c2776d2 100644 --- a/include/reactos/libs/fullfat/ff_memory.h +++ b/include/reactos/libs/fullfat/ff_memory.h @@ -41,19 +41,125 @@ #include "ff_config.h" #include "ff_types.h" +#ifdef __REACTOS__ +// defined in fullfat.c +void *FF_Malloc(FF_T_UINT32 allocSize); +void FF_Free(void *pBuffer); +#endif +/* + HT changed type of aOffset to u32 +*/ //---------- PROTOTYPES -FF_T_UINT8 FF_getChar (FF_T_UINT8 *pBuffer, FF_T_UINT16 offset); -FF_T_UINT16 FF_getShort (FF_T_UINT8 *pBuffer, FF_T_UINT16 offset); -FF_T_UINT32 FF_getLong (FF_T_UINT8 *pBuffer, FF_T_UINT16 offset); +#if defined(FF_LITTLE_ENDIAN) -void FF_putChar (FF_T_UINT8 *pBuffer, FF_T_UINT16 offset, FF_T_UINT8 Value); -void FF_putShort (FF_T_UINT8 *pBuffer, FF_T_UINT16 offset, FF_T_UINT16 Value); -void FF_putLong (FF_T_UINT8 *pBuffer, FF_T_UINT16 offset, FF_T_UINT32 Value); +typedef struct { + FF_T_UINT8 u8_0; + FF_T_UINT8 u8_1; +} FF_T_SHORT; -void *FF_Malloc(FF_T_UINT32 allocSize); -void FF_Free(void *pBuffer); +typedef struct { + FF_T_UINT8 u8_0; + FF_T_UINT8 u8_1; + FF_T_UINT8 u8_2; + FF_T_UINT8 u8_3; +} FF_T_LONG; + +#elif defined(FF_BIG_ENDIAN) + +typedef struct { + FF_T_UINT8 u8_1; + FF_T_UINT8 u8_0; +} FF_T_SHORT; + +typedef struct { + FF_T_UINT8 u8_3; + FF_T_UINT8 u8_2; + FF_T_UINT8 u8_1; + FF_T_UINT8 u8_0; +} FF_T_LONG; + +#else + +#error Little or Big Endian? - Please set an endianess in ff_config.h + +#endif + +//! 16-bit union. +typedef union { + FF_T_UINT16 u16; + FF_T_SHORT bytes; +} FF_T_UN16; + +//! 32-bit union. +typedef union { + FF_T_UINT32 u32; + FF_T_LONG bytes; +} FF_T_UN32; + +/* HT inlined these functions: + */ + +#ifdef FF_INLINE_MEMORY_ACCESS + +FF_INLINE FF_T_UINT8 FF_getChar(FF_T_UINT8 *pBuffer, FF_T_UINT32 aOffset) +{ + return (FF_T_UINT8) (pBuffer[aOffset]); +} + +FF_INLINE FF_T_UINT16 FF_getShort(FF_T_UINT8 *pBuffer, FF_T_UINT32 aOffset) +{ + FF_T_UN16 u16; + pBuffer += aOffset; + u16.bytes.u8_1 = pBuffer[1]; + u16.bytes.u8_0 = pBuffer[0]; + return u16.u16; +} + +FF_INLINE FF_T_UINT32 FF_getLong(FF_T_UINT8 *pBuffer, FF_T_UINT32 aOffset) { + FF_T_UN32 u32; + pBuffer += aOffset; + u32.bytes.u8_3 = pBuffer[3]; + u32.bytes.u8_2 = pBuffer[2]; + u32.bytes.u8_1 = pBuffer[1]; + u32.bytes.u8_0 = pBuffer[0]; + return u32.u32; +} + +FF_INLINE void FF_putChar(FF_T_UINT8 *pBuffer, FF_T_UINT32 aOffset, FF_T_UINT8 Value) { + pBuffer[aOffset] = Value; +} + +FF_INLINE void FF_putShort(FF_T_UINT8 *pBuffer, FF_T_UINT32 aOffset, FF_T_UINT16 Value) { + FF_T_UN16 u16; + u16.u16 = Value; + pBuffer += aOffset; + pBuffer[0] = u16.bytes.u8_0; + pBuffer[1] = u16.bytes.u8_1; +} + +FF_INLINE void FF_putLong(FF_T_UINT8 *pBuffer, FF_T_UINT32 aOffset, FF_T_UINT32 Value) { + FF_T_UN32 u32; + u32.u32 = Value; + pBuffer += aOffset; + pBuffer[0] = u32.bytes.u8_0; + pBuffer[1] = u32.bytes.u8_1; + pBuffer[2] = u32.bytes.u8_2; + pBuffer[3] = u32.bytes.u8_3; +} + +#else + +FF_T_UINT8 FF_getChar(FF_T_UINT8 *pBuffer, FF_T_UINT32 aOffset); +FF_T_UINT16 FF_getShort(FF_T_UINT8 *pBuffer, FF_T_UINT32 aOffset); +FF_T_UINT32 FF_getLong(FF_T_UINT8 *pBuffer, FF_T_UINT32 aOffset); +void FF_putChar(FF_T_UINT8 *pBuffer, FF_T_UINT32 aOffset, FF_T_UINT8 Value); +void FF_putShort(FF_T_UINT8 *pBuffer, FF_T_UINT32 aOffset, FF_T_UINT16 Value); +void FF_putLong(FF_T_UINT8 *pBuffer, FF_T_UINT32 aOffset, FF_T_UINT32 Value); + + +#endif #endif diff --git a/include/reactos/libs/fullfat/ff_string.h b/include/reactos/libs/fullfat/ff_string.h index e3789102e4b..0820391f56c 100644 --- a/include/reactos/libs/fullfat/ff_string.h +++ b/include/reactos/libs/fullfat/ff_string.h @@ -44,11 +44,35 @@ #define _FF_STRING_H_ #include "ff_types.h" +#include "ff_config.h" +#include -void FF_tolower (FF_T_INT8 *string, FF_T_UINT32 strLen); -void FF_toupper (FF_T_INT8 *string, FF_T_UINT32 strLen); -FF_T_BOOL FF_strmatch (const FF_T_INT8 *str1, const FF_T_INT8 *str2, FF_T_UINT16 len); -FF_T_INT8 *FF_strtok (const FF_T_INT8 *string, FF_T_INT8 *token, FF_T_UINT16 *tokenNumber, FF_T_BOOL *last, FF_T_UINT16 Length); -FF_T_BOOL FF_wildcompare(const FF_T_INT8 *pszWildCard, const FF_T_INT8 *pszString); +#ifdef WIN32 +#define FF_stricmp stricmp +#else +#define FF_stricmp strcasecmp +#endif + +#ifdef FF_UNICODE_SUPPORT +void FF_tolower (FF_T_WCHAR *string, FF_T_UINT32 strLen); +void FF_toupper (FF_T_WCHAR *string, FF_T_UINT32 strLen); +FF_T_BOOL FF_strmatch (const FF_T_WCHAR *str1, const FF_T_WCHAR *str2, FF_T_UINT16 len); +FF_T_WCHAR *FF_strtok (const FF_T_WCHAR *string, FF_T_WCHAR *token, FF_T_UINT16 *tokenNumber, FF_T_BOOL *last, FF_T_UINT16 Length); +FF_T_BOOL FF_wildcompare (const FF_T_WCHAR *pszWildCard, const FF_T_WCHAR *pszString); + +// ASCII to UTF16 and UTF16 to ASCII routines. -- These are lossy routines, and are only for converting ASCII to UTF-16 +// and the equivalent back to ASCII. Do not use them for international text. +void FF_cstrtowcs(FF_T_WCHAR *wcsDest, const FF_T_INT8 *szpSource); +void FF_wcstocstr(FF_T_INT8 *szpDest, const FF_T_WCHAR *wcsSource); +void FF_cstrntowcs(FF_T_WCHAR *wcsDest, const FF_T_INT8 *szpSource, FF_T_UINT32 len); +void FF_wcsntocstr(FF_T_INT8 *szpDest, const FF_T_WCHAR *wcsSource, FF_T_UINT32 len); + +#else +void FF_tolower (FF_T_INT8 *string, FF_T_UINT32 strLen); +void FF_toupper (FF_T_INT8 *string, FF_T_UINT32 strLen); +FF_T_BOOL FF_strmatch (const FF_T_INT8 *str1, const FF_T_INT8 *str2, FF_T_UINT16 len); +FF_T_INT8 *FF_strtok (const FF_T_INT8 *string, FF_T_INT8 *token, FF_T_UINT16 *tokenNumber, FF_T_BOOL *last, FF_T_UINT16 Length); +FF_T_BOOL FF_wildcompare (const FF_T_INT8 *pszWildCard, const FF_T_INT8 *pszString); +#endif #endif diff --git a/include/reactos/libs/fullfat/ff_types.h b/include/reactos/libs/fullfat/ff_types.h index 59a599670a3..0a3d5c280f1 100644 --- a/include/reactos/libs/fullfat/ff_types.h +++ b/include/reactos/libs/fullfat/ff_types.h @@ -61,6 +61,11 @@ typedef long FF_T_INT32; ///< 32 bit default integer. typedef unsigned long FF_T_UINT32; ///< 32 bit unsigned integer. typedef signed long FF_T_SINT32; ///< 32 bit signed integer. +//---------------- Platform Integer Sizes +typedef int FF_T_INT; +typedef unsigned int FF_T_UINT; +typedef signed int FF_T_SINT; + #ifdef FF_64_NUM_SUPPORT //---------------- 64 BIT INTEGERS // If you cannot define these, then make sure you see ff_config.h typedef long long FF_T_INT64; // about 64-bit number support. @@ -70,5 +75,9 @@ typedef signed long long FF_T_SINT64; // > 4GB in bytes if you cannot support 64 #endif typedef FF_T_SINT32 FF_ERROR; ///< A special error code type to ease some inconsistencies in Error reporting. +#ifdef FF_UNICODE_SUPPORT +#include +typedef wchar_t FF_T_WCHAR; ///< Unicode UTF-16 Charachter type, for FullFAT when UNICODE is enabled. +#endif #endif // end of include guard diff --git a/include/reactos/libs/fullfat/ff_unicode.h b/include/reactos/libs/fullfat/ff_unicode.h new file mode 100644 index 00000000000..9f0cbecb4cd --- /dev/null +++ b/include/reactos/libs/fullfat/ff_unicode.h @@ -0,0 +1,60 @@ +/***************************************************************************** + * FullFAT - High Performance, Thread-Safe Embedded FAT File-System * + * Copyright (C) 2009 James Walmsley (james@worm.me.uk) * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + * * + * IMPORTANT NOTICE: * + * ================= * + * Alternative Licensing is available directly from the Copyright holder, * + * (James Walmsley). For more information consult LICENSING.TXT to obtain * + * a Commercial license. * + * * + * See RESTRICTIONS.TXT for extra restrictions on the use of FullFAT. * + * * + * Removing the above notice is illegal and will invalidate this license. * + ***************************************************************************** + * See http://worm.me.uk/fullfat for more information. * + * Or http://fullfat.googlecode.com/ for latest releases and the wiki. * + *****************************************************************************/ + +/** + * @file ff_unicode.c + * @author James Walmsley + * @ingroup UNICODE + * + **/ + +#ifndef _FF_UNICODE_H_ +#define _FF_UNICODE_H_ + +#include "ff_config.h" +#include "ff_types.h" +#include "ff_error.h" + +// UTF8 / UTF16 Transformation Functions + +FF_T_UINT FF_GetUtf16SequenceLen (FF_T_UINT16 usLeadChar); +FF_T_SINT32 FF_Utf8ctoUtf16c (FF_T_UINT16 *utf16Dest, const FF_T_UINT8 *utf8Source, FF_T_UINT32 ulSize); +FF_T_SINT32 FF_Utf16ctoUtf8c (FF_T_UINT8 *utf8Dest, const FF_T_UINT16 *utf16Source, FF_T_UINT32 ulSize); + +// UTF16 / UTF32 Transformation Functions + +FF_T_SINT32 FF_Utf16ctoUtf32c(FF_T_UINT32 *utf32Dest, const FF_T_UINT16 *utf16Source); +FF_T_SINT32 FF_Utf32ctoUtf16c(FF_T_UINT16 *utf16Dest, FF_T_UINT32 utf32char, FF_T_UINT32 ulSize); + +// String transformations +FF_T_SINT32 FF_Utf32stoUtf8s(FF_T_UINT8 *Utf8String, FF_T_UINT32 *Utf32String); + +#endif diff --git a/include/reactos/libs/fullfat/fullfat.h b/include/reactos/libs/fullfat/fullfat.h index dd8da071cf5..18aa2bb2549 100644 --- a/include/reactos/libs/fullfat/fullfat.h +++ b/include/reactos/libs/fullfat/fullfat.h @@ -32,6 +32,10 @@ #ifndef _FULLFAT_H_ #define _FULLFAT_H_ +#ifdef __cplusplus +extern "C" { +#endif + #include "ff_config.h" #include "ff_ioman.h" #include "ff_fat.h" @@ -41,6 +45,11 @@ #include "ff_crc.h" #include "ff_hash.h" #include "ff_string.h" +#include "ff_unicode.h" +//#include "ff_format.h" +#ifdef __cplusplus +} // extern "C" +#endif #endif diff --git a/include/reactos/win32k/ntuser.h b/include/reactos/win32k/ntuser.h index 484a3a4b84c..71ea1772fc6 100644 --- a/include/reactos/win32k/ntuser.h +++ b/include/reactos/win32k/ntuser.h @@ -1761,18 +1761,11 @@ NtUserGetClassInfo(HINSTANCE hInstance, LPWSTR *ppszMenuName, BOOL Ansi); -INT -NTAPI -NtUserGetClassName(HWND hWnd, - PUNICODE_STRING ClassName, - BOOL Ansi); -#if 0 // Real NtUserGetClassName INT NTAPI NtUserGetClassName(HWND hWnd, BOOL Real, // 0 GetClassNameW, 1 RealGetWindowClassA/W PUNICODE_STRING ClassName); -#endif HANDLE NTAPI @@ -2411,28 +2404,28 @@ NtUserQueryWindow( HWND hWnd, DWORD Index); -DWORD +BOOL NTAPI NtUserRealInternalGetMessage( - DWORD dwUnknown1, - DWORD dwUnknown2, - DWORD dwUnknown3, - DWORD dwUnknown4, - DWORD dwUnknown5, - DWORD dwUnknown6); + LPMSG lpMsg, + HWND hWnd, + UINT wMsgFilterMin, + UINT wMsgFilterMax, + UINT wRemoveMsg, + BOOL bGMSG); -DWORD +HWND NTAPI NtUserRealChildWindowFromPoint( - DWORD Unknown0, - DWORD Unknown1, - DWORD Unknown2); + HWND Parent, + LONG x, + LONG y); -DWORD +BOOL NTAPI NtUserRealWaitMessageEx( - DWORD dwUnknown1, - DWORD dwUnknown2); + DWORD dwWakeMask, + UINT uTimeout); BOOL NTAPI diff --git a/lib/3rdparty/fullfat/ff_crc.c b/lib/3rdparty/fullfat/ff_crc.c index 9c6ea469334..2b6f76ba5a2 100644 --- a/lib/3rdparty/fullfat/ff_crc.c +++ b/lib/3rdparty/fullfat/ff_crc.c @@ -41,7 +41,68 @@ #include "ff_crc.h" -static const FF_T_UINT8 CRC16_Low[256] = + +static const FF_T_UINT32 crc32_table[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, + 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, + 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, + 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, + 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, + 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, + 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, + 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, + 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106, + 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, + 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, + 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, + 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, + 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, + 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, + 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, + 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, + 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, + 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, + 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, + 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, + 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, + 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, + 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, + 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, + 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, + 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, + 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, + 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, + 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, + 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, + 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, + 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D +}; + +FF_T_UINT32 FF_GetCRC32(FF_T_UINT8 *pbyData, FF_T_UINT32 stLength) { + + register FF_T_UINT32 crc = 0xFFFFFFFF; + + while(stLength--) { + crc = ((crc >> 8) & 0x00FFFFFF) ^ crc32_table[(crc^*pbyData++) & 0x000000FF]; + } + + return (crc ^ 0xFFFFFFFF); +} + + + + +static const FF_T_UINT8 crc16_table_low[256] = { 0x000, 0x0c1, 0x081, 0x040, 0x001, 0x0c0, 0x080, 0x041, 0x001, 0x0c0, 0x080, 0x041, 0x000, 0x0c1, 0x081, 0x040, @@ -77,7 +138,7 @@ static const FF_T_UINT8 CRC16_Low[256] = 0x001, 0x0c0, 0x080, 0x041, 0x000, 0x0c1, 0x081, 0x040, }; -static const FF_T_UINT8 CRC16_High[256] = +static const FF_T_UINT8 crc16_table_high[256] = { 0x000, 0x0c0, 0x0c1, 0x001, 0x0c3, 0x003, 0x002, 0x0c2, 0x0c6, 0x006, 0x007, 0x0c7, 0x005, 0x0c5, 0x0c4, 0x004, @@ -130,15 +191,15 @@ FF_T_UINT16 FF_GetCRC16(FF_T_UINT8 *pbyData, FF_T_UINT32 stLength) { while (stLength--) { bTableValue = (FF_T_UINT8)((wCRC & 0x00FF) ^ *pbyData++); - wCRC = (FF_T_UINT16)(((CRC16_High[bTableValue]) << 8) - + (CRC16_Low[bTableValue] ^ ((wCRC >> 8) & 0x00FF))); + wCRC = (FF_T_UINT16)(((crc16_table_high[bTableValue]) << 8) + + (crc16_table_low[bTableValue] ^ ((wCRC >> 8) & 0x00FF))); } return wCRC; } -static const FF_T_UINT8 byCRCLookUpTable[256] = +static const FF_T_UINT8 crc8_table[256] = { 0, 94, 188, 226, 97, 63, 221, 131, 194, 156, 126, 32, 163, 253, 31, 65, @@ -188,7 +249,7 @@ FF_T_UINT8 FF_GetCRC8(FF_T_UINT8 *pbyData, FF_T_UINT32 stLength) { FF_T_UINT8 byCRC = 0, byData; while (stLength--) { byData = *pbyData++; - byCRC = byCRCLookUpTable[(byCRC ^ byData)]; + byCRC = crc8_table[(byCRC ^ byData)]; } return byCRC; } diff --git a/lib/3rdparty/fullfat/ff_dir.c b/lib/3rdparty/fullfat/ff_dir.c index 6bba0b79020..b9767352b8e 100644 --- a/lib/3rdparty/fullfat/ff_dir.c +++ b/lib/3rdparty/fullfat/ff_dir.c @@ -42,16 +42,44 @@ #include "ff_dir.h" #include "ff_string.h" +#include "ff_unicode.h" #include + +#ifdef FF_UNICODE_SUPPORT +#include +#endif + +#ifdef WIN32 +#else +#include // tolower() +int strcasecmp(const char *s1, const char *s2) +{ + unsigned char c1,c2; + do { + c1 = *s1++; + c2 = *s2++; + c1 = (unsigned char) tolower( (unsigned char) c1); + c2 = (unsigned char) tolower( (unsigned char) c2); + } + while((c1 == c2) && (c1 != '\0')); + return (int) c1-c2; +} +#endif + + +#ifdef FF_UNICODE_SUPPORT +static void FF_ProcessShortName(FF_T_WCHAR *name); +#else static void FF_ProcessShortName(FF_T_INT8 *name); +#endif void FF_lockDIR(FF_IOMAN *pIoman) { - FF_PendSemaphore(pIoman->pSemaphore); // Use Semaphore to protect FAT modifications. + FF_PendSemaphore(pIoman->pSemaphore); // Use Semaphore to protect DIR modifications. { while((pIoman->Locks & FF_DIR_LOCK)) { FF_ReleaseSemaphore(pIoman->pSemaphore); - FF_Yield(); // Keep Releasing and Yielding until we have the Fat protector. + FF_Yield(); // Keep Releasing and Yielding until we have the DIR protector. FF_PendSemaphore(pIoman->pSemaphore); } pIoman->Locks |= FF_DIR_LOCK; @@ -77,24 +105,28 @@ static FF_T_UINT8 FF_CreateChkSum(const FF_T_UINT8 *pa_pShortName) { return ChkSum; } -FF_T_SINT8 FF_FindNextInDir(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_DIRENT *pDirent) { + +FF_ERROR FF_FindNextInDir(FF_IOMAN *pIoman, FF_DIRENT *pDirent, FF_FETCH_CONTEXT *pFetchContext) { - FF_T_UINT8 numLFNs; - FF_T_UINT8 EntryBuffer[32]; + FF_T_UINT8 numLFNs; + FF_T_UINT8 EntryBuffer[32]; + FF_ERROR Error; if(!pIoman) { return FF_ERR_NULL_POINTER; } - //pDirent->NumLFNs = 0; - for(; pDirent->CurrentItem < 0xFFFF; pDirent->CurrentItem += 1) { - if(FF_FetchEntry(pIoman, DirCluster, pDirent->CurrentItem, EntryBuffer)) { - return -2; + + Error = FF_FetchEntryWithContext(pIoman, pDirent->CurrentItem, pFetchContext, EntryBuffer); + + if(Error) { + return Error; } + if(EntryBuffer[0] != 0xE5) { if(FF_isEndOfDir(EntryBuffer)){ - return -2; + return FF_ERR_DIR_END_OF_DIR; } pDirent->Attrib = FF_getChar(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB)); if((pDirent->Attrib & FF_FAT_ATTR_LFN) == FF_FAT_ATTR_LFN) { @@ -102,8 +134,11 @@ FF_T_SINT8 FF_FindNextInDir(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_DIRENT numLFNs = (FF_T_UINT8)(EntryBuffer[0] & ~0x40); //pDirent->NumLFNs = numLFNs; #ifdef FF_LFN_SUPPORT - FF_PopulateLongDirent(pIoman, pDirent, DirCluster, pDirent->CurrentItem); - return 0; + Error = FF_PopulateLongDirent(pIoman, pDirent, pDirent->CurrentItem, pFetchContext); + if(Error) { + return Error; + } + return FF_ERR_NONE; #else pDirent->CurrentItem += (numLFNs - 1); #endif @@ -113,421 +148,309 @@ FF_T_SINT8 FF_FindNextInDir(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_DIRENT } else { FF_PopulateShortDirent(pIoman, pDirent, EntryBuffer); pDirent->CurrentItem += 1; - return 0; + return FF_ERR_NONE; } } } - return -1; + return FF_ERR_DIR_END_OF_DIR; } -/* -FF_T_BOOL FF_ShortNameExists(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *name) { - FF_DIRENT MyDir; +#ifdef FF_UNICODE_SUPPORT +static FF_T_BOOL FF_ShortNameExists(FF_IOMAN *pIoman, FF_T_UINT32 ulDirCluster, FF_T_WCHAR *szShortName, FF_ERROR *pError) { +#else +static FF_T_BOOL FF_ShortNameExists(FF_IOMAN *pIoman, FF_T_UINT32 ulDirCluster, FF_T_INT8 *szShortName, FF_ERROR *pError) { +#endif - if(FF_FindEntry(pIoman, DirCluster, name, &MyDir, FF_FALSE)) { - return FF_FALSE; - } + FF_T_UINT16 i; + FF_T_UINT8 EntryBuffer[32]; + FF_T_UINT8 Attrib; + FF_FETCH_CONTEXT FetchContext; + +#ifdef FF_UNICODE_SUPPORT + FF_T_WCHAR UTF16EntryBuffer[32]; +#endif - return FF_TRUE; -}*/ +#ifdef FF_HASH_CACHE + FF_T_UINT32 ulHash; +#endif -FF_T_BOOL FF_ShortNameExists(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *name) { + *pError = FF_ERR_NONE; - FF_T_UINT16 i; - FF_T_UINT8 EntryBuffer[32]; - FF_T_UINT8 Attrib; -#ifdef FF_HASH_TABLE_SUPPORT - - if(!FF_DirHashed(pIoman, DirCluster)) { - for(i = 0; i < 0xFFFF; i++) { - if(FF_FetchEntry(pIoman, DirCluster, i, EntryBuffer)) { - FF_SetDirHashed(pIoman, DirCluster); - break; - } - Attrib = FF_getChar(EntryBuffer, FF_FAT_DIRENT_ATTRIB); - if(FF_getChar(EntryBuffer, 0x00) != 0xE5) { - if(Attrib != FF_FAT_ATTR_LFN) { - if(FF_isEndOfDir(EntryBuffer)) { - FF_SetDirHashed(pIoman, DirCluster); - break; - } - FF_ProcessShortName((FF_T_INT8 *)EntryBuffer); - FF_AddDirentHash(pIoman, DirCluster, FF_GetCRC16((FF_T_UINT8 *) EntryBuffer, strlen(EntryBuffer))); - } - } - } - } +#ifdef FF_HASH_CACHE + if(!FF_DirHashed(pIoman, ulDirCluster)) { + // Hash the directory + FF_HashDir(pIoman, ulDirCluster); + } #if FF_HASH_FUNCTION == CRC16 - if(FF_CheckDirentHash(pIoman, DirCluster, (FF_T_UINT32)FF_GetCRC16((FF_T_UINT8 *) name, strlen(name)))) { + ulHash = (FF_T_UINT32) FF_GetCRC16((FF_T_UINT8 *) szShortName, strlen(szShortName)); #elif FF_HASH_FUNCTION == CRC8 - if(FF_CheckDirentHash(pIoman, DirCluster, (FF_T_UINT32)FF_GetCRC8((FF_T_UINT8 *) name, strlen(name)))) { + ulHash = (FF_T_UINT32) FF_GetCRC8((FF_T_UINT8 *) szShortName, strlen(szShortName)); +#endif + + if(!FF_CheckDirentHash(pIoman, ulDirCluster, ulHash)) { + return FF_FALSE; + } + +#endif + + *pError = FF_InitEntryFetch(pIoman, ulDirCluster, &FetchContext); + if(*pError) { + return FF_FALSE; + } + + for(i = 0; i < 0xFFFF; i++) { + *pError = FF_FetchEntryWithContext(pIoman, i, &FetchContext, EntryBuffer); + if(*pError) { + FF_CleanupEntryFetch(pIoman, &FetchContext); + return FF_FALSE; + } + Attrib = FF_getChar(EntryBuffer, FF_FAT_DIRENT_ATTRIB); + if(FF_getChar(EntryBuffer, 0x00) != 0xE5) { + if(Attrib != FF_FAT_ATTR_LFN) { +#ifdef FF_UNICODE_SUPPORT + // Convert Entry Buffer into UTF16 + FF_cstrntowcs(UTF16EntryBuffer, (FF_T_INT8 *) EntryBuffer, 32); + FF_ProcessShortName(UTF16EntryBuffer); #else - { + FF_ProcessShortName((FF_T_INT8 *)EntryBuffer); #endif + if(FF_isEndOfDir(EntryBuffer)) { + FF_CleanupEntryFetch(pIoman, &FetchContext); + return FF_FALSE; + } +#ifdef FF_UNICODE_SUPPORT + if(wcscmp(szShortName, UTF16EntryBuffer) == 0) { +#else + if(strcmp(szShortName, (FF_T_INT8 *)EntryBuffer) == 0) { #endif - - for(i = 0; i < 0xFFFF; i++) { - FF_FetchEntry(pIoman, DirCluster, i, EntryBuffer); - Attrib = FF_getChar(EntryBuffer, FF_FAT_DIRENT_ATTRIB); - if(FF_getChar(EntryBuffer, 0x00) != 0xE5) { - if(Attrib != FF_FAT_ATTR_LFN) { - FF_ProcessShortName((FF_T_INT8 *)EntryBuffer); - if(FF_isEndOfDir(EntryBuffer)) { - return FF_FALSE; - } - if(strcmp(name, (FF_T_INT8 *)EntryBuffer) == 0) { - return FF_TRUE; - } - } + FF_CleanupEntryFetch(pIoman, &FetchContext); + return FF_TRUE; } } -#ifdef FF_HASH_TABLE_SUPPORT } -#endif - - return FF_FALSE; + } + + FF_CleanupEntryFetch(pIoman, &FetchContext); + return FF_FALSE; } -FF_T_UINT32 FF_FindEntryInDir(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *name, FF_T_UINT8 pa_Attrib, FF_DIRENT *pDirent) { - FF_T_UINT16 fnameLen; - FF_T_UINT16 compareLength; - FF_T_UINT16 nameLen; - FF_T_INT8 Filename[FF_MAX_FILENAME]; - FF_T_INT8 MyFname[FF_MAX_FILENAME]; - FF_T_BOOL bBreak = FF_FALSE; - - pDirent->CurrentItem = 0; - nameLen = (FF_T_UINT16) strlen(name); +#ifdef FF_UNICODE_SUPPORT +FF_T_UINT32 FF_FindEntryInDir(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, const FF_T_WCHAR *name, FF_T_UINT8 pa_Attrib, FF_DIRENT *pDirent, FF_ERROR *pError) { +#else +FF_T_UINT32 FF_FindEntryInDir(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, const FF_T_INT8 *name, FF_T_UINT8 pa_Attrib, FF_DIRENT *pDirent, FF_ERROR *pError) { +#endif - while(!bBreak) { - if(FF_FindNextInDir(pIoman, DirCluster, pDirent)) { - break; // end of dir, file not found! - } + FF_FETCH_CONTEXT FetchContext; + FF_T_UINT8 *src; // Pointer to read from pBuffer + FF_T_UINT8 *lastSrc; +#ifdef FF_UNICODE_UTF8_SUPPORT + FF_T_SINT32 utf8Error; + FF_T_UINT8 bSurrogate = FF_FALSE; +#endif +#ifdef FF_UNICODE_SUPPORT + FF_T_WCHAR *ptr; // Pointer to store a LFN +#else + FF_T_INT8 *ptr; // Pointer to store a LFN +#endif +#ifdef FF_UNICODE_SUPPORT + FF_T_WCHAR *lastPtr = pDirent->FileName + sizeof(pDirent->FileName); +#else + FF_T_INT8 *lastPtr = pDirent->FileName + sizeof(pDirent->FileName); +#endif + FF_T_UINT8 CheckSum = 0; + FF_T_UINT8 lastAttrib; + FF_T_INT8 totalLFNs = 0; + FF_T_INT8 numLFNs = 0; + FF_T_INT32 i; + FF_T_UINT16 lfnItem = 0; - if((pDirent->Attrib & pa_Attrib) == pa_Attrib){ - strcpy(Filename, pDirent->FileName); - fnameLen = (FF_T_UINT16) strlen(Filename); - FF_tolower(Filename, (FF_T_UINT32) fnameLen); - if(nameLen < FF_MAX_FILENAME) { - memcpy(MyFname, name, nameLen + 1); - } else { - memcpy(MyFname, name, FF_MAX_FILENAME); - MyFname[FF_MAX_FILENAME - 1] = '\0'; - } - FF_tolower(MyFname, (FF_T_UINT32) nameLen); - if(nameLen > fnameLen) { - compareLength = nameLen; - } else { - compareLength = fnameLen; - } - if(strncmp(MyFname, Filename, (FF_T_UINT32) compareLength) == 0) { - // Object found! - return pDirent->ObjectCluster; // Return the cluster number - } - } - } - - return 0; -} - -/* -#define FF_DIR_LFN_TRAVERSED 0x01 -#define FF_DIR_LFN_DELETED 0x02 - -FF_T_SINT8 FF_PopulateLongBufEntry(FF_IOMAN *pIoman, FF_BUFFER **ppBuffer, FF_DIRENT *pDirent) { - // Relative positions! - FF_T_UINT32 RelBlockNum; - FF_T_UINT32 RelBlockPos = FF_getMinorBlockEntry(pIoman, pDirent->CurrentItem, 32); - FF_T_UINT32 iItemLBA; - FF_T_INT8 *DirBuffer = ((*ppBuffer)->pBuffer + (RelBlockPos * 32)); - FF_T_UINT8 numLFNs = (FF_getChar(DirBuffer, (FF_T_UINT16) 0) & ~0x40); - FF_T_UINT16 x,i,y,myShort, lenlfn = 0; - FF_T_UINT32 CurrentCluster; - FF_T_SINT8 RetVal = FF_ERR_NONE; - FF_T_INT8 ShortName[13]; - FF_T_UINT8 CheckSum = FF_getChar(DirBuffer, FF_FAT_LFN_CHECKSUM); - - while(numLFNs > 0) { - - for(i = 0, y = 0; i < 5; i++, y += 2) { - pDirent->FileName[i + ((numLFNs - 1) * 13)] = DirBuffer[FF_FAT_LFN_NAME_1 + y]; - lenlfn++; - } - - for(i = 0, y = 0; i < 6; i++, y += 2) { - pDirent->FileName[i + ((numLFNs - 1) * 13) + 5] = DirBuffer[FF_FAT_LFN_NAME_2 + y]; - lenlfn++; - } - - for(i = 0, y = 0; i < 2; i++, y += 2) { - pDirent->FileName[i + ((numLFNs - 1) * 13) + 11] = DirBuffer[FF_FAT_LFN_NAME_3 + y]; - lenlfn++; - } - numLFNs--; - pDirent->CurrentItem += 1; - - CurrentCluster = FF_getClusterChainNumber(pIoman, pDirent->CurrentItem, 32); - RelBlockNum = FF_getMajorBlockNumber(pIoman, pDirent->CurrentItem, 32); - RelBlockPos = FF_getMinorBlockEntry(pIoman, pDirent->CurrentItem, 32); - iItemLBA = FF_Cluster2LBA(pIoman, pDirent->AddrCurrentCluster) + RelBlockNum; - - if(CurrentCluster > pDirent->CurrentCluster) { - pDirent->AddrCurrentCluster = FF_TraverseFAT(pIoman, pDirent->AddrCurrentCluster, 1); - pDirent->CurrentCluster += 1; - iItemLBA = FF_Cluster2LBA(pIoman, pDirent->AddrCurrentCluster) + RelBlockNum; - FF_ReleaseBuffer(pIoman, *ppBuffer); - *ppBuffer = FF_GetBuffer(pIoman, iItemLBA, FF_MODE_READ); - RetVal |= FF_DIR_LFN_TRAVERSED; - } else if(iItemLBA > ((*ppBuffer)->Sector)) { - FF_ReleaseBuffer(pIoman, *ppBuffer); - *ppBuffer = FF_GetBuffer(pIoman, iItemLBA, FF_MODE_READ); - RetVal |= FF_DIR_LFN_TRAVERSED; - } - - DirBuffer = ((*ppBuffer)->pBuffer + (RelBlockPos * 32)); - } - - if(FF_getChar(DirBuffer, (FF_T_UINT16) 0) == FF_FAT_DELETED) { - RetVal |= FF_DIR_LFN_DELETED; - return RetVal; - } - - pDirent->FileName[lenlfn] = '\0'; - - // Process the ShortName Entry - memcpy(ShortName, DirBuffer, 11); - if(CheckSum != FF_CreateChkSum(ShortName)) { - FF_ProcessShortName(ShortName); - strcpy(pDirent->FileName, ShortName); - } else { - FF_ProcessShortName(ShortName); - } - - myShort = FF_getShort(DirBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_HIGH)); - pDirent->ObjectCluster = (FF_T_UINT32) (myShort << 16); - myShort = FF_getShort(DirBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_LOW)); - pDirent->ObjectCluster |= myShort; - - // Get the filesize. - pDirent->Filesize = FF_getLong(DirBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_FILESIZE)); - // Get the attribute. - pDirent->Attrib = FF_getChar(DirBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB)); - - return RetVal; -}*/ - -/* -FF_T_SINT8 FF_FindEntry(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *Name, FF_DIRENT *pDirent, FF_T_BOOL LFNs) { - - FF_T_UINT32 iItemLBA; - FF_BUFFER *pBuffer; - FF_T_INT8 *DirBuffer; - FF_T_UINT32 fatEntry = DirCluster; - FF_T_UINT32 i,x; - FF_T_UINT32 numLFNs; - FF_T_UINT16 NameLen, DirentNameLen; - FF_T_BOOL Compare = FF_FALSE; - FF_T_SINT8 RetVal = 0; - FF_T_UINT16 RelEntry; + pError = NULL; pDirent->CurrentItem = 0; - pDirent->AddrCurrentCluster = DirCluster; - pDirent->CurrentCluster = 0; - pDirent->DirCluster = DirCluster; + pDirent->Attrib = 0; - do { - - pDirent->AddrCurrentCluster = fatEntry; - iItemLBA = FF_Cluster2LBA(pIoman, pDirent->AddrCurrentCluster); + FF_InitEntryFetch(pIoman, DirCluster, &FetchContext); - for(i = 0; i < pIoman->pPartition->SectorsPerCluster; i++) { - - if(FF_getClusterChainNumber(pIoman, pDirent->CurrentItem, 32) > pDirent->CurrentCluster) { - break; - } - - pBuffer = FF_GetBuffer(pIoman, iItemLBA + i, FF_MODE_READ); - { - if(!pBuffer) { - return FF_ERR_DEVICE_DRIVER_FAILED; - } - pBuffer->Persistance = 1; - RelEntry = FF_getMinorBlockEntry(pIoman, pDirent->CurrentItem, 32); - for(x = RelEntry; x < (pIoman->BlkSize / 32); x++) { - if(FF_getMajorBlockNumber(pIoman, pDirent->CurrentItem, 32) > i) { - break; - } - if(FF_getClusterChainNumber(pIoman, pDirent->CurrentItem, 32) > pDirent->CurrentCluster) { - break; - } - RelEntry = FF_getMinorBlockEntry(pIoman, pDirent->CurrentItem, 32); - x = RelEntry; - if(x >= (pIoman->BlkSize / 32)) { - break; - } - DirBuffer = (pBuffer->pBuffer + (32 * x)); - // Process each entry and Compare to Name! - if(FF_getChar(DirBuffer, (FF_T_UINT16) 0) != FF_FAT_DELETED) { - if(DirBuffer[0] == 0x00) { - FF_ReleaseBuffer(pIoman, pBuffer); - return FF_ERR_DIR_END_OF_DIR; - } - pDirent->Attrib = FF_getChar(DirBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB)); - if((pDirent->Attrib & FF_FAT_ATTR_LFN) == FF_FAT_ATTR_LFN) { - numLFNs = (FF_T_UINT8)(DirBuffer[0] & ~0x40); - if(LFNs) { - RetVal = FF_PopulateLongBufEntry(pIoman, &pBuffer, pDirent); - if((RetVal & FF_DIR_LFN_DELETED)) { - Compare = FF_FALSE; - RetVal &= ~FF_DIR_LFN_DELETED; - } else { - Compare = FF_TRUE; - } - - pDirent->CurrentItem += 1; - } else { - pDirent->CurrentItem += numLFNs; - } - - } else { - FF_PopulateShortDirent(pDirent, DirBuffer); - Compare = FF_TRUE; - pDirent->CurrentItem += 1; - } - - if(Compare) { - // Compare the Items - NameLen = strlen(Name); - DirentNameLen = strlen(pDirent->FileName); - - if(NameLen == DirentNameLen) { // Names are same length, possible match. - if(FF_StrMatch(Name, pDirent->FileName, NameLen)) { - FF_ReleaseBuffer(pIoman, pBuffer); - return FF_ERR_NONE; // Success Item found! - } - } - Compare = FF_FALSE; - } - - if((RetVal & FF_DIR_LFN_TRAVERSED)) { - break; - } - - } else { - pDirent->CurrentItem += 1; - } - } - } - FF_ReleaseBuffer(pIoman, pBuffer); - if((RetVal & FF_DIR_LFN_TRAVERSED)) { - break; - } - } - - // Traverse! - - if((RetVal & FF_DIR_LFN_TRAVERSED)) { - RetVal = FF_ERR_NONE; - fatEntry = pDirent->AddrCurrentCluster; - } else { - if(FF_getClusterChainNumber(pIoman, pDirent->CurrentItem, 32) > pDirent->CurrentCluster) { - fatEntry = FF_getFatEntry(pIoman, pDirent->AddrCurrentCluster); - pDirent->AddrCurrentCluster = FF_TraverseFAT(pIoman, pDirent->AddrCurrentCluster, 1); - pDirent->CurrentCluster += 1; - } - } - } while(!FF_isEndOfChain(pIoman, fatEntry)); - - return FF_ERR_DIR_END_OF_DIR; -}*/ - - -/** - * @private - **/ -/*FF_T_UINT32 FF_FindEntry(FF_IOMAN *pIoman, FF_T_SINT8 *path, FF_T_UINT8 pa_Attrib, FF_DIRENT *pDirent) { - - FF_T_INT32 retVal; - FF_T_INT8 name[FF_MAX_FILENAME]; - FF_T_INT8 Filename[FF_MAX_FILENAME]; - FF_T_UINT16 fnameLen; - FF_T_UINT16 compareLength; - FF_T_UINT16 nameLen; - FF_T_UINT16 i = strlen(path); - - - while(i != 0) { - if(path[i] == '\\' || path[i] == '/') { + while(pDirent->CurrentItem < 0xFFFF) { + if (FF_FetchEntryWithContext(pIoman, pDirent->CurrentItem, &FetchContext, NULL)) { break; } - i--; - } - - if(i == 0) { - i = 1; - } - - nameLen = strlen((path + i)); - strncpy(name, (path + i), nameLen); - name[nameLen] = '\0'; - - - if(FF_FindFirst(pIoman, pDirent, path)) { - return 0; // file not found. - } - - if((pDirent->Attrib & pa_Attrib) == pa_Attrib){ - strcpy(Filename, pDirent->FileName); - fnameLen = (FF_T_UINT16) strlen(Filename); - FF_tolower(Filename, (FF_T_UINT32) fnameLen); - FF_tolower(name, (FF_T_UINT32) nameLen); - if(nameLen > fnameLen) { - compareLength = nameLen; - } else { - compareLength = fnameLen; - } - if(strncmp(name, Filename, (FF_T_UINT32) compareLength) == 0) { - // Object found!! - return pDirent->ObjectCluster; // Return the cluster number - } - } - - while(1) { - if(FF_FindNext(pIoman, pDirent)) { - return 0; // end of dir, file not found! - } - - if((pDirent->Attrib & pa_Attrib) == pa_Attrib){ - strcpy(Filename, pDirent->FileName); - fnameLen = (FF_T_UINT16) strlen(Filename); - FF_tolower(Filename, (FF_T_UINT32) fnameLen); - FF_tolower(name, (FF_T_UINT32) nameLen); - if(nameLen > fnameLen) { - compareLength = nameLen; - } else { - compareLength = fnameLen; + lastSrc = FetchContext.pBuffer->pBuffer + pIoman->BlkSize; + for (src = FetchContext.pBuffer->pBuffer; src < lastSrc; src += 32, pDirent->CurrentItem++) { + if (FF_isEndOfDir(src)) { // 0x00: end-of-dir + FF_CleanupEntryFetch(pIoman, &FetchContext); + return 0; } - if(strncmp(name, Filename, (FF_T_UINT32) compareLength) == 0) { - // Object found! - return pDirent->ObjectCluster; // Return the cluster number + if (src[0] == 0xE5) { // Entry not used + pDirent->Attrib = 0; + continue; } + lastAttrib = pDirent->Attrib; + pDirent->Attrib = FF_getChar(src, FF_FAT_DIRENT_ATTRIB); + if((pDirent->Attrib & FF_FAT_ATTR_LFN) == FF_FAT_ATTR_LFN) { + // LFN Processing +#ifdef FF_LFN_SUPPORT + if (numLFNs == 0 || (lastAttrib & FF_FAT_ATTR_LFN) != FF_FAT_ATTR_LFN) { + totalLFNs = numLFNs = (FF_T_UINT8)(src[0] & ~0x40); + lfnItem = pDirent->CurrentItem; + CheckSum = FF_getChar(src, FF_FAT_LFN_CHECKSUM); + lastPtr[-1] = '\0'; + } + if (numLFNs) { + numLFNs--; + ptr = pDirent->FileName + (numLFNs * 13); + + /* + This section needs to extract the name and do the comparison + dependent on UNICODE settings in the ff_config.h file. + */ +#ifdef FF_UNICODE_SUPPORT + // Add UTF-16 Routine here + memcpy(ptr, &src[FF_FAT_LFN_NAME_1], 10); // Copy first 5 UTF-16 chars (10 bytes). + ptr += 5; // Increment Filename pointer 5 utf16 chars. + + memcpy(ptr, &src[FF_FAT_LFN_NAME_2], 12); //Copy next 6 chars (12 bytes). + ptr += 6; + + memcpy(ptr, &src[FF_FAT_LFN_NAME_3], 4); // You're getting the idea by now! + ptr += 2; + +#endif +#ifdef FF_UNICODE_UTF8_SUPPORT + // UTF-8 Routine here + for(i = 0; i < 5 && ptr < lastPtr; i++) { + // Was there a surrogate sequence? -- Add handling here. + utf8Error = FF_Utf16ctoUtf8c((FF_T_UINT8 *) ptr, (FF_T_UINT16 *) &src[FF_FAT_LFN_NAME_1 + (2*i)], lastPtr - ptr); + if(utf8Error > 0) { + ptr += utf8Error; + + } else { + if(utf8Error == FF_ERR_UNICODE_INVALID_SEQUENCE) { + // Handle potential surrogate sequence across entries. + + } + } + } + + for(i = 0; i < 6 && ptr < lastPtr; i++) { + // Was there a surrogate sequence? -- To add handling here. + utf8Error = FF_Utf16ctoUtf8c((FF_T_UINT8 *) ptr, (FF_T_UINT16 *) &src[FF_FAT_LFN_NAME_2 + (2*i)], lastPtr - ptr); + if(utf8Error > 0) { + ptr += utf8Error; + } else { + if(utf8Error == FF_ERR_UNICODE_INVALID_SEQUENCE) { + // Handle potential surrogate sequence across entries. + } + } + } + + for(i = 0; i < 2 && ptr < lastPtr; i++) { + // Was there a surrogate sequence? -- To add handling here. + utf8Error = FF_Utf16ctoUtf8c((FF_T_UINT8 *) ptr, (FF_T_UINT16 *) &src[FF_FAT_LFN_NAME_3 + (2*i)], lastPtr - ptr); + if(utf8Error > 0) { + ptr += utf8Error; + } else { + if(utf8Error == FF_ERR_UNICODE_INVALID_SEQUENCE) { + // Handle potential surrogate sequence across entries. + } + } + } + +#endif +#ifndef FF_UNICODE_SUPPORT +#ifndef FF_UNICODE_UTF8_SUPPORT + for(i = 0; i < 10 && ptr < lastPtr; i += 2) + *(ptr++) = src[FF_FAT_LFN_NAME_1 + i]; + + for(i = 0; i < 12 && ptr < lastPtr; i += 2) + *(ptr++) = src[FF_FAT_LFN_NAME_2 + i]; + + for(i = 0; i < 4 && ptr < lastPtr; i += 2) + *(ptr++) = src[FF_FAT_LFN_NAME_3 + i]; + + if (numLFNs == totalLFNs-1 && ptr < lastPtr) + *ptr = '\0'; // Important when name len is multiple of 13 +#endif +#endif + if (numLFNs == totalLFNs-1 && ptr < lastPtr) + *ptr = '\0'; // Important when name len is multiple of 13 + + } +#endif + continue; + } + if ((pDirent->Attrib & FF_FAT_ATTR_VOLID) == FF_FAT_ATTR_VOLID) { + totalLFNs = 0; + continue; + } +#ifdef FF_LFN_SUPPORT + if(!totalLFNs || CheckSum != FF_CreateChkSum(src)) +#endif + { +#ifdef FF_UNICODE_SUPPORT + for(i = 0; i < 11; i++) { + pDirent->FileName[i] = (FF_T_WCHAR) src[i]; + } + FF_ProcessShortName(pDirent->FileName); +#else + memcpy(pDirent->FileName, src, 11); + FF_ProcessShortName(pDirent->FileName); +#endif + totalLFNs = 0; + } + + if((pDirent->Attrib & pa_Attrib) == pa_Attrib){ +#ifdef FF_UNICODE_SUPPORT + if(!wcsicmp(name, pDirent->FileName)) { +#else + if (!FF_stricmp(name, pDirent->FileName)) { +#endif + // Finally get the complete information +#ifdef FF_LFN_SUPPORT + if (totalLFNs) { + FF_PopulateLongDirent(pIoman, pDirent, lfnItem, &FetchContext); + } else +#endif + { + FF_PopulateShortDirent(pIoman, pDirent, src); + } + // Object found! + FF_CleanupEntryFetch(pIoman, &FetchContext); + return pDirent->ObjectCluster; // Return the cluster number + } + } + totalLFNs = 0; } - } + } // for (src = FetchContext.pBuffer->pBuffer; src < lastSrc; src += 32, pDirent->CurrentItem++) + + FF_CleanupEntryFetch(pIoman, &FetchContext); + return 0; -}*/ +} + + /** * @private **/ - -FF_T_UINT32 FF_FindDir(FF_IOMAN *pIoman, const FF_T_INT8 *path, FF_T_UINT16 pathLen) { +#ifdef FF_UNICODE_SUPPORT +FF_T_UINT32 FF_FindDir(FF_IOMAN *pIoman, const FF_T_WCHAR *path, FF_T_UINT16 pathLen, FF_ERROR *pError) { +#else +FF_T_UINT32 FF_FindDir(FF_IOMAN *pIoman, const FF_T_INT8 *path, FF_T_UINT16 pathLen, FF_ERROR *pError) { +#endif FF_T_UINT32 dirCluster = pIoman->pPartition->RootDirCluster; - FF_T_INT8 mytoken[FF_MAX_FILENAME]; - FF_T_INT8 *token; +#ifdef FF_UNICODE_SUPPORT + FF_T_WCHAR mytoken[FF_MAX_FILENAME]; + FF_T_WCHAR *token; +#else + FF_T_INT8 mytoken[FF_MAX_FILENAME]; + FF_T_INT8 *token; +#endif + FF_T_UINT16 it = 0; // Re-entrancy Variables for FF_strtok() FF_T_BOOL last = FF_FALSE; FF_DIRENT MyDir; @@ -535,7 +458,9 @@ FF_T_UINT32 FF_FindDir(FF_IOMAN *pIoman, const FF_T_INT8 *path, FF_T_UINT16 path FF_T_UINT32 i; #endif - if(pathLen == 1) { // Must be the root dir! (/ or \) + *pError = FF_ERR_NONE; + + if(pathLen <= 1) { // Must be the root dir! (/ or \) return pIoman->pPartition->RootDirCluster; } @@ -547,8 +472,14 @@ FF_T_UINT32 FF_FindDir(FF_IOMAN *pIoman, const FF_T_INT8 *path, FF_T_UINT16 path FF_PendSemaphore(pIoman->pSemaphore); // Thread safety on shared object! { for(i = 0; i < FF_PATH_CACHE_DEPTH; i++) { +#ifdef FF_UNICODE_SUPPORT + if(wcslen(pIoman->pPartition->PathCache[i].Path) == pathLen) { + if(FF_strmatch(pIoman->pPartition->PathCache[i].Path, path, pathLen)) { +#else if(strlen(pIoman->pPartition->PathCache[i].Path) == pathLen) { if(FF_strmatch(pIoman->pPartition->PathCache[i].Path, path, pathLen)) { +#endif + FF_ReleaseSemaphore(pIoman->pSemaphore); return pIoman->pPartition->PathCache[i].DirCluster; } @@ -561,9 +492,13 @@ FF_T_UINT32 FF_FindDir(FF_IOMAN *pIoman, const FF_T_INT8 *path, FF_T_UINT16 path token = FF_strtok(path, mytoken, &it, &last, pathLen); do{ - //lastDirCluster = dirCluster; MyDir.CurrentItem = 0; - dirCluster = FF_FindEntryInDir(pIoman, dirCluster, token, FF_FAT_ATTR_DIR, &MyDir); + dirCluster = FF_FindEntryInDir(pIoman, dirCluster, token, FF_FAT_ATTR_DIR, &MyDir, pError); + + if(*pError) { + return 0; + } + /*if(dirCluster == 0 && MyDir.CurrentItem == 2 && MyDir.FileName[0] == '.') { // .. Dir Entry pointing to root dir. dirCluster = pIoman->pPartition->RootDirCluster; }*/ @@ -575,7 +510,11 @@ FF_T_UINT32 FF_FindDir(FF_IOMAN *pIoman, const FF_T_INT8 *path, FF_T_UINT16 path FF_PendSemaphore(pIoman->pSemaphore); { if(pathLen < FF_MAX_PATH) { // Ensure the PATH won't cause a buffer overrun. +#ifdef FF_UNICODE_SUPPORT + memcpy(pIoman->pPartition->PathCache[pIoman->pPartition->PCIndex].Path, path, pathLen * sizeof(FF_T_WCHAR)); +#else memcpy(pIoman->pPartition->PathCache[pIoman->pPartition->PCIndex].Path, path, pathLen); +#endif pIoman->pPartition->PathCache[pIoman->pPartition->PCIndex].Path[pathLen] = '\0'; pIoman->pPartition->PathCache[pIoman->pPartition->PCIndex].DirCluster = dirCluster; #ifdef FF_HASH_TABLE_SUPPORT @@ -594,132 +533,81 @@ FF_T_UINT32 FF_FindDir(FF_IOMAN *pIoman, const FF_T_INT8 *path, FF_T_UINT16 path return dirCluster; } -/* -FF_T_UINT32 FF_FindDir(FF_IOMAN *pIoman, FF_T_INT8 *path, FF_T_UINT16 pathLen) { - FF_T_UINT32 dirCluster = pIoman->pPartition->RootDirCluster; - FF_T_INT8 mytoken[FF_MAX_FILENAME]; - FF_T_INT8 *token; - FF_T_UINT16 it = 0; // Re-entrancy Variables for FF_strtok() - FF_T_BOOL last = FF_FALSE; - FF_DIRENT MyDir; - if(pathLen == 1) { // Must be the root dir! (/ or \) - return pIoman->pPartition->RootDirCluster; - } - - if(path[pathLen-1] == '\\' || path[pathLen-1] == '/') { - pathLen--; - } - - token = FF_strtok(path, mytoken, &it, &last, pathLen); - - do{ - //lastDirCluster = dirCluster; - MyDir.CurrentItem = 0; - if(FF_FindEntry(pIoman, dirCluster, token, &MyDir, FF_TRUE)) { - return 0; - } else { - dirCluster = MyDir.ObjectCluster; - } - if(MyDir.Attrib != FF_FAT_ATTR_DIR) { - return 0; - } - if(dirCluster == 0 && MyDir.CurrentItem == 2 && MyDir.FileName[0] == '.') { // .. Dir Entry pointing to root dir. - dirCluster = pIoman->pPartition->RootDirCluster; - } - token = FF_strtok(path, mytoken, &it, &last, pathLen); - }while(token != NULL); - - return dirCluster; -} -*/ - -#ifdef FF_LFN_SUPPORT +#if defined(FF_SHORTNAME_CASE) /** * @private - **//* -FF_T_SINT8 FF_getLFN(FF_IOMAN *pIoman, FF_BUFFER *pBuffer, FF_DIRENT *pDirent, FF_T_INT8 *filename) { - - FF_T_UINT8 numLFNs; - FF_T_UINT16 lenlfn = 0; - FF_T_UINT8 tester; - FF_T_UINT16 i,y; - FF_T_UINT32 CurrentCluster; - FF_T_UINT32 fatEntry; - FF_T_UINT8 *buffer = pBuffer->pBuffer; - FF_T_UINT32 Sector = pBuffer->Sector; - FF_T_UINT32 Entry = FF_getMinorBlockEntry(pIoman, pDirent->CurrentItem, 32); - - tester = FF_getChar(pBuffer->pBuffer, (FF_T_UINT16)(Entry * 32)); - numLFNs = (FF_T_UINT8) (tester & ~0x40); - - while(numLFNs > 0) { - if(FF_getClusterChainNumber(pIoman, pDirent->CurrentItem, 32) > pDirent->CurrentCluster) { - FF_ReleaseBuffer(pIoman, pBuffer); - fatEntry = FF_getFatEntry(pIoman, pDirent->DirCluster); - if(fatEntry == (FF_T_UINT32) FF_ERR_DEVICE_DRIVER_FAILED) { - return FF_ERR_DEVICE_DRIVER_FAILED; - } - - if(FF_isEndOfChain(pIoman, fatEntry)) { - CurrentCluster = pDirent->DirCluster; - // ERROR THIS SHOULD NOT OCCUR! - } else { - CurrentCluster = fatEntry; - } - - pBuffer = FF_GetBuffer(pIoman, FF_getRealLBA(pIoman, FF_Cluster2LBA(pIoman, CurrentCluster)), FF_MODE_READ); - if(!pBuffer) { - return FF_ERR_DEVICE_DRIVER_FAILED; - } - Entry = 0; + * For short-name entries, NT/XP etc store case information in byte 0x0c + * Use this to show proper case of "README.txt" or "source.H" + **/ +#ifdef FF_UNICODE_SUPPORT +static void FF_CaseShortName(FF_T_WCHAR *name, FF_T_UINT8 attrib) { +#else +static void FF_CaseShortName(FF_T_INT8 *name, FF_T_UINT8 attrib) { +#endif + FF_T_UINT8 testAttrib = FF_FAT_CASE_ATTR_BASE; + for (; *name; name++) { + if (*name == '.') { + testAttrib = FF_FAT_CASE_ATTR_EXT; + } else if ((attrib & testAttrib)) { + if (*name >= 'A' && *name <= 'Z') + *name += 0x20; + } else if (*name >= 'a' && *name <= 'z') { + *name -= 0x20; } - - if(Entry > 15) { - FF_ReleaseBuffer(pIoman, pBuffer); - Sector += 1; - pBuffer = FF_GetBuffer(pIoman, Sector, FF_MODE_READ); - if(!pBuffer) { - return FF_ERR_DEVICE_DRIVER_FAILED; - } - buffer = pBuffer->pBuffer; - Entry = 0; - } - - for(i = 0, y = 0; i < 5; i++, y += 2) { - filename[i + ((numLFNs - 1) * 13)] = buffer[(Entry * 32) + FF_FAT_LFN_NAME_1 + y]; - lenlfn++; - } - - for(i = 0, y = 0; i < 6; i++, y += 2) { - filename[i + ((numLFNs - 1) * 13) + 5] = buffer[(Entry * 32) + FF_FAT_LFN_NAME_2 + y]; - lenlfn++; - } - - for(i = 0, y = 0; i < 2; i++, y += 2) { - filename[i + ((numLFNs - 1) * 13) + 11] = buffer[(Entry * 32) + FF_FAT_LFN_NAME_3 + y]; - lenlfn++; - } - - numLFNs--; - - Entry++; - pDirent->CurrentItem += 1; } - - filename[lenlfn] = '\0'; - - return 0; -}*/ +} #endif /** * @private **/ + +#ifdef FF_UNICODE_SUPPORT +static void FF_ProcessShortName(FF_T_WCHAR *name) { + FF_T_WCHAR shortName[13]; + FF_T_WCHAR *ptr = name; +#else static void FF_ProcessShortName(FF_T_INT8 *name) { FF_T_INT8 shortName[13]; + FF_T_INT8 *ptr = name; +#endif FF_T_UINT8 i; +#ifdef FF_UNICODE_SUPPORT + memcpy(shortName, name, 11 * sizeof(FF_T_WCHAR)); +#else memcpy(shortName, name, 11); +#endif + + for(i = 0; i < 11; i++) { + if(shortName[i] == 0x20) { + if (i >= 8) + break; + i = 7; + } else { + if (i == 8) + *(ptr++) = '.'; + *(ptr++) = shortName[i]; + } + } + *ptr = '\0'; +} + +/* +#ifdef FF_UNICODE_SUPPORT +static void FF_ProcessShortName(FF_T_WCHAR *name) { + FF_T_WCHAR shortName[13]; +#else +static void FF_ProcessShortName(FF_T_INT8 *name) { + FF_T_INT8 shortName[13]; +#endif + + FF_T_UINT8 i; +#ifdef FF_UNICODE_SUPPORT + memcpy(shortName, name, 11 * sizeof(FF_T_WCHAR)); +#else + memcpy(shortName, name, 11); +#endif for(i = 0; i < 8; i++) { if(shortName[i] == 0x20) { @@ -745,7 +633,7 @@ static void FF_ProcessShortName(FF_T_INT8 *name) { name[i] = '\0'; } -} +}*/ #ifdef FF_TIME_SUPPORT static void FF_PlaceTime(FF_T_UINT8 *EntryBuffer, FF_T_UINT32 Offset) { @@ -790,28 +678,40 @@ static void FF_GetDate(FF_SYSTEMTIME *pTime, FF_T_UINT8 *EntryBuffer, FF_T_UINT3 pTime->Month = (((myShort & 0x01E0) >> 5) & 0x000F); pTime->Day = myShort & 0x01F; } - - - #endif void FF_PopulateShortDirent(FF_IOMAN *pIoman, FF_DIRENT *pDirent, FF_T_UINT8 *EntryBuffer) { FF_T_UINT16 myShort; - +#ifdef FF_UNICODE_SUPPORT + FF_T_WCHAR UTF16EntryBuffer[12]; + FF_cstrntowcs(UTF16EntryBuffer, (FF_T_INT8 *) EntryBuffer, 11); + memcpy(pDirent->FileName, UTF16EntryBuffer, 11 * sizeof(FF_T_WCHAR)); +#else memcpy(pDirent->FileName, EntryBuffer, 11); // Copy the filename into the Dirent object. +#endif +#if defined(FF_LFN_SUPPORT) && defined(FF_INCLUDE_SHORT_NAME) + memcpy(pDirent->ShortName, EntryBuffer, 11); + pDirent->ShortName[11] = '\0'; + FF_ProcessShortName(pDirent->ShortName); // Format the shortname, for pleasant viewing. + +#endif FF_ProcessShortName(pDirent->FileName); // Format the shortname, for pleasant viewing. #ifdef FF_HASH_TABLE_SUPPORT -#if FF_HASH_FUNCTION == CRC16 +/*#if FF_HASH_FUNCTION == CRC16 FF_AddDirentHash(pIoman, pDirent->DirCluster, (FF_T_UINT32)FF_GetCRC16((FF_T_UINT8 *) pDirent->FileName, strlen(pDirent->FileName))); #elif FF_HASH_FUNCTION == CRC8 FF_AddDirentHash(pIoman, pDirent->DirCluster, (FF_T_UINT32)FF_GetCRC8((FF_T_UINT8 *) pDirent->FileName, strlen(pDirent->FileName))); -#endif +#endif*/ #else - pIoman = NULL; + pIoman = NULL; // Silence a compiler warning, about not referencing pIoman. #endif +#ifdef FF_UNICODE_SUPPORT + FF_tolower(pDirent->FileName, (FF_T_UINT32)wcslen(pDirent->FileName)); +#else FF_tolower(pDirent->FileName, (FF_T_UINT32)strlen(pDirent->FileName)); +#endif // Get the item's Cluster address. myShort = FF_getShort(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_HIGH)); @@ -837,68 +737,167 @@ void FF_PopulateShortDirent(FF_IOMAN *pIoman, FF_DIRENT *pDirent, FF_T_UINT8 *En pDirent->Attrib = FF_getChar(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB)); } -FF_T_SINT8 FF_FetchEntry(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT16 nEntry, FF_T_UINT8 *buffer) { - FF_BUFFER *pBuffer; - FF_T_UINT32 itemLBA; - FF_T_UINT32 chainLength = FF_GetChainLength(pIoman, DirCluster, NULL); // BottleNeck - FF_T_UINT32 clusterNum = FF_getClusterChainNumber (pIoman, nEntry, (FF_T_UINT16)32); - FF_T_UINT32 relItem = FF_getMinorBlockEntry (pIoman, nEntry, (FF_T_UINT16)32); - FF_T_UINT32 clusterAddress = FF_TraverseFAT(pIoman, DirCluster, clusterNum); // BottleNeck +/* + Initialises a context object for FF_FetchEntryWithContext() +*/ +FF_ERROR FF_InitEntryFetch(FF_IOMAN *pIoman, FF_T_UINT32 ulDirCluster, FF_FETCH_CONTEXT *pContext) { + + FF_ERROR Error; + + memset(pContext, 0, sizeof(FF_FETCH_CONTEXT)); + + pContext->ulChainLength = FF_GetChainLength(pIoman, ulDirCluster, NULL, &Error); // Get the total length of the chain. + if(Error) { + return Error; + } + pContext->ulDirCluster = ulDirCluster; + pContext->ulCurrentClusterLCN = ulDirCluster; + pContext->ulCurrentClusterNum = 0; + pContext->ulCurrentEntry = 0; if(pIoman->pPartition->Type != FF_T_FAT32) { - if(DirCluster == pIoman->pPartition->RootDirCluster) { - chainLength = pIoman->pPartition->RootDirSectors / pIoman->pPartition->SectorsPerCluster; - if(!chainLength) { // Some media has RootDirSectors < SectorsPerCluster. This is wrong, as it should be atleast 1 cluster! - chainLength = 1; + // Handle Root Dirs that don't have cluster chains! + if(pContext->ulDirCluster == pIoman->pPartition->RootDirCluster) { + // This is a RootDIR, special consideration needs to be made, because it doesn't have a Cluster chain! + pContext->ulChainLength = pIoman->pPartition->RootDirSectors / pIoman->pPartition->SectorsPerCluster; + if(!pContext->ulChainLength) { // Some media has RootDirSectors < SectorsPerCluster. This is wrong, as it should be atleast 1 cluster! + pContext->ulChainLength = 1; } - clusterAddress = DirCluster; - clusterNum = 0; - if(nEntry > ((pIoman->pPartition->RootDirSectors * pIoman->pPartition->BlkSize) / 32)) { + } + } + + return FF_ERR_NONE; +} + +void FF_CleanupEntryFetch(FF_IOMAN *pIoman, FF_FETCH_CONTEXT *pContext) { + if(pContext->pBuffer) { + FF_ReleaseBuffer(pIoman, pContext->pBuffer); + pContext->pBuffer = NULL; + } +} + +FF_ERROR FF_FetchEntryWithContext(FF_IOMAN *pIoman, FF_T_UINT32 ulEntry, FF_FETCH_CONTEXT *pContext, FF_T_UINT8 *pEntryBuffer) { + + FF_T_UINT32 ulItemLBA; + FF_T_UINT32 ulRelItem; + FF_T_UINT32 ulClusterNum; + FF_ERROR Error; + + ulClusterNum = FF_getClusterChainNumber(pIoman, ulEntry, (FF_T_UINT16)32); + ulRelItem = FF_getMinorBlockEntry (pIoman, ulEntry, (FF_T_UINT16)32); + + if(ulClusterNum != pContext->ulCurrentClusterNum) { + // Traverse the fat gently! + if(ulClusterNum > pContext->ulCurrentClusterNum) { + pContext->ulCurrentClusterLCN = FF_TraverseFAT(pIoman, pContext->ulCurrentClusterLCN, (ulClusterNum - pContext->ulCurrentClusterNum), &Error); + if(Error) { + return Error; + } + } else { + pContext->ulCurrentClusterLCN = FF_TraverseFAT(pIoman, pContext->ulDirCluster, ulClusterNum, &Error); + if(Error) { + return Error; + } + } + pContext->ulCurrentClusterNum = ulClusterNum; + } + + if(pIoman->pPartition->Type != FF_T_FAT32) { + // Handle Root Dirs that don't have cluster chains! + if(pContext->ulDirCluster == pIoman->pPartition->RootDirCluster) { + // This is a RootDIR, special consideration needs to be made, because it doesn't have a Cluster chain! + pContext->ulCurrentClusterLCN = pContext->ulDirCluster; + ulClusterNum = 0; + if(ulEntry > ((pIoman->pPartition->RootDirSectors * pIoman->pPartition->BlkSize) / 32)) { return FF_ERR_DIR_END_OF_DIR; } } } - - if((clusterNum + 1) > chainLength) { + + if((ulClusterNum + 1) > pContext->ulChainLength) { return FF_ERR_DIR_END_OF_DIR; // End of Dir was reached! } - itemLBA = FF_Cluster2LBA(pIoman, clusterAddress) + FF_getMajorBlockNumber(pIoman, nEntry, (FF_T_UINT16)32); - itemLBA = FF_getRealLBA (pIoman, itemLBA) + FF_getMinorBlockNumber(pIoman, relItem, (FF_T_UINT16)32); - - pBuffer = FF_GetBuffer(pIoman, itemLBA, FF_MODE_READ); - { - memcpy(buffer, (pBuffer->pBuffer + (relItem*32)), 32); - pBuffer->Persistance = 1; + ulItemLBA = FF_Cluster2LBA (pIoman, pContext->ulCurrentClusterLCN) + FF_getMajorBlockNumber(pIoman, ulEntry, (FF_T_UINT16)32); + ulItemLBA = FF_getRealLBA (pIoman, ulItemLBA) + FF_getMinorBlockNumber(pIoman, ulRelItem, (FF_T_UINT16)32); + + if(!pContext->pBuffer || (pContext->pBuffer->Sector != ulItemLBA)) { + if(pContext->pBuffer) { + FF_ReleaseBuffer(pIoman, pContext->pBuffer); + } + pContext->pBuffer = FF_GetBuffer(pIoman, ulItemLBA, FF_MODE_READ); + if(!pContext->pBuffer) { + return FF_ERR_DEVICE_DRIVER_FAILED; + } } - FF_ReleaseBuffer(pIoman, pBuffer); - + + if (pEntryBuffer) { // HT Because it might be called with NULL + memcpy(pEntryBuffer, (pContext->pBuffer->pBuffer + (ulRelItem*32)), 32); + } + return FF_ERR_NONE; } -FF_T_SINT8 FF_PushEntry(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT16 nEntry, FF_T_UINT8 *buffer) { - FF_BUFFER *pBuffer; - FF_T_UINT32 itemLBA; - FF_T_UINT32 chainLength = FF_GetChainLength(pIoman, DirCluster, NULL); // BottleNeck - FF_T_UINT32 clusterNum = FF_getClusterChainNumber (pIoman, nEntry, (FF_T_UINT16)32); - FF_T_UINT32 relItem = FF_getMinorBlockEntry (pIoman, nEntry, (FF_T_UINT16)32); - FF_T_UINT32 clusterAddress = FF_TraverseFAT(pIoman, DirCluster, clusterNum); // BottleNeck - - if((clusterNum + 1) > chainLength) { +FF_ERROR FF_PushEntryWithContext(FF_IOMAN *pIoman, FF_T_UINT32 ulEntry, FF_FETCH_CONTEXT *pContext, FF_T_UINT8 *pEntryBuffer) { + FF_T_UINT32 ulItemLBA; + FF_T_UINT32 ulRelItem; + FF_T_UINT32 ulClusterNum; + FF_ERROR Error; + + ulClusterNum = FF_getClusterChainNumber(pIoman, ulEntry, (FF_T_UINT16)32); + ulRelItem = FF_getMinorBlockEntry (pIoman, ulEntry, (FF_T_UINT16)32); + + if(ulClusterNum != pContext->ulCurrentClusterNum) { + // Traverse the fat gently! + if(ulClusterNum > pContext->ulCurrentClusterNum) { + pContext->ulCurrentClusterLCN = FF_TraverseFAT(pIoman, pContext->ulCurrentClusterLCN, (ulClusterNum - pContext->ulCurrentClusterNum), &Error); + if(Error) { + return Error; + } + } else { + pContext->ulCurrentClusterLCN = FF_TraverseFAT(pIoman, pContext->ulDirCluster, ulClusterNum, &Error); + if(Error) { + return Error; + } + } + pContext->ulCurrentClusterNum = ulClusterNum; + } + + if(pIoman->pPartition->Type != FF_T_FAT32) { + // Handle Root Dirs that don't have cluster chains! + if(pContext->ulDirCluster == pIoman->pPartition->RootDirCluster) { + // This is a RootDIR, special consideration needs to be made, because it doesn't have a Cluster chain! + pContext->ulCurrentClusterLCN = pContext->ulDirCluster; + ulClusterNum = 0; + if(ulEntry > ((pIoman->pPartition->RootDirSectors * pIoman->pPartition->BlkSize) / 32)) { + return FF_ERR_DIR_END_OF_DIR; + } + } + } + + if((ulClusterNum + 1) > pContext->ulChainLength) { return FF_ERR_DIR_END_OF_DIR; // End of Dir was reached! } - itemLBA = FF_Cluster2LBA(pIoman, clusterAddress) + FF_getMajorBlockNumber(pIoman, nEntry, (FF_T_UINT16)32); - itemLBA = FF_getRealLBA (pIoman, itemLBA) + FF_getMinorBlockNumber(pIoman, relItem, (FF_T_UINT16)32); - - pBuffer = FF_GetBuffer(pIoman, itemLBA, FF_MODE_WRITE); - { - memcpy((pBuffer->pBuffer + (relItem*32)), buffer, 32); + ulItemLBA = FF_Cluster2LBA (pIoman, pContext->ulCurrentClusterLCN) + FF_getMajorBlockNumber(pIoman, ulEntry, (FF_T_UINT16)32); + ulItemLBA = FF_getRealLBA (pIoman, ulItemLBA) + FF_getMinorBlockNumber(pIoman, ulRelItem, (FF_T_UINT16)32); + + if(!pContext->pBuffer || (pContext->pBuffer->Sector != ulItemLBA)) { + if(pContext->pBuffer) { + FF_ReleaseBuffer(pIoman, pContext->pBuffer); + } + pContext->pBuffer = FF_GetBuffer(pIoman, ulItemLBA, FF_MODE_READ); + if(!pContext->pBuffer) { + return FF_ERR_DEVICE_DRIVER_FAILED; + } } - FF_ReleaseBuffer(pIoman, pBuffer); - - return 0; + + memcpy((pContext->pBuffer->pBuffer + (ulRelItem*32)), pEntryBuffer, 32); + pContext->pBuffer->Mode = FF_MODE_WRITE; + pContext->pBuffer->Modified = FF_TRUE; + + return FF_ERR_NONE; } @@ -906,14 +905,24 @@ FF_T_SINT8 FF_PushEntry(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT16 nE * @private **/ FF_ERROR FF_GetEntry(FF_IOMAN *pIoman, FF_T_UINT16 nEntry, FF_T_UINT32 DirCluster, FF_DIRENT *pDirent) { - FF_T_UINT8 EntryBuffer[32]; - FF_T_UINT8 numLFNs; + FF_T_UINT8 EntryBuffer[32]; + FF_T_UINT8 numLFNs; + FF_FETCH_CONTEXT FetchContext; + FF_ERROR Error; + + Error = FF_InitEntryFetch(pIoman, DirCluster, &FetchContext); + if(Error) { + return Error; + } - if(FF_FetchEntry(pIoman, DirCluster, nEntry, EntryBuffer)) { - return FF_ERR_DIR_END_OF_DIR; + Error = FF_FetchEntryWithContext(pIoman, nEntry, &FetchContext, EntryBuffer); + if(Error) { + FF_CleanupEntryFetch(pIoman, &FetchContext); + return Error; } if(EntryBuffer[0] != 0xE5) { if(FF_isEndOfDir(EntryBuffer)){ + FF_CleanupEntryFetch(pIoman, &FetchContext); return FF_ERR_DIR_END_OF_DIR; } @@ -923,8 +932,12 @@ FF_ERROR FF_GetEntry(FF_IOMAN *pIoman, FF_T_UINT16 nEntry, FF_T_UINT32 DirCluste // LFN Processing numLFNs = (FF_T_UINT8)(EntryBuffer[0] & ~0x40); #ifdef FF_LFN_SUPPORT - FF_PopulateLongDirent(pIoman, pDirent, DirCluster, nEntry); - return 0; + Error = FF_PopulateLongDirent(pIoman, pDirent, nEntry, &FetchContext); + FF_CleanupEntryFetch(pIoman, &FetchContext); + if(Error) { + return Error; + } + return FF_ERR_NONE; #else pDirent->CurrentItem += (numLFNs - 1); #endif @@ -934,9 +947,12 @@ FF_ERROR FF_GetEntry(FF_IOMAN *pIoman, FF_T_UINT16 nEntry, FF_T_UINT32 DirCluste } else { FF_PopulateShortDirent(pIoman, pDirent, EntryBuffer); pDirent->CurrentItem += 1; + FF_CleanupEntryFetch(pIoman, &FetchContext); return 0; } } + + FF_CleanupEntryFetch(pIoman, &FetchContext); return FF_ERR_NONE; } @@ -947,55 +963,123 @@ FF_T_BOOL FF_isEndOfDir(FF_T_UINT8 *EntryBuffer) { return FF_FALSE; } -#ifdef FF_HASH_TABLE_SUPPORT -FF_ERROR FF_AddDirentHash(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT32 nHash) { +#ifdef FF_HASH_CACHE +FF_ERROR FF_AddDirentHash(FF_IOMAN *pIoman, FF_T_UINT32 ulDirCluster, FF_T_UINT32 ulHash) { FF_T_UINT32 i; FF_HASH_TABLE pHash = NULL; - for(i = 0; i < FF_PATH_CACHE_DEPTH; i++) { - if(pIoman->pPartition->PathCache[i].DirCluster == DirCluster) { - pHash = pIoman->pPartition->PathCache[i].pHashTable; + for(i = 0; i < FF_HASH_CACHE_DEPTH; i++) { + if(pIoman->HashCache[i].ulDirCluster == ulDirCluster) { + pHash = pIoman->HashCache[i].pHashTable; break; } } if(pHash) { - FF_SetHash(pHash, nHash); + FF_SetHash(pHash, ulHash); } return FF_ERR_NONE; } -FF_T_BOOL FF_CheckDirentHash(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT32 nHash) { +FF_T_BOOL FF_CheckDirentHash(FF_IOMAN *pIoman, FF_T_UINT32 ulDirCluster, FF_T_UINT32 ulHash) { FF_T_UINT32 i; FF_HASH_TABLE pHash = NULL; - for(i = 0; i < FF_PATH_CACHE_DEPTH; i++) { - if(pIoman->pPartition->PathCache[i].DirCluster == DirCluster) { - pHash = pIoman->pPartition->PathCache[i].pHashTable; + for(i = 0; i < FF_HASH_CACHE_DEPTH; i++) { + if(pIoman->HashCache[i].ulDirCluster == ulDirCluster) { + pHash = pIoman->HashCache[i].pHashTable; break; } } if(pHash) { - return FF_isHashSet(pHash, nHash); + return FF_isHashSet(pHash, ulHash); } return FF_FALSE; } -FF_T_BOOL FF_DirHashed(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster) { +FF_T_BOOL FF_DirHashed(FF_IOMAN *pIoman, FF_T_UINT32 ulDirCluster) { FF_T_UINT32 i; - for(i = 0; i < FF_PATH_CACHE_DEPTH; i++) { - if(pIoman->pPartition->PathCache[i].DirCluster == DirCluster) { - if(pIoman->pPartition->PathCache[i].bHashed) { - return FF_TRUE; - } + for(i = 0; i < FF_HASH_CACHE_DEPTH; i++) { + if(pIoman->HashCache[i].ulDirCluster == ulDirCluster) { + return FF_TRUE; } } return FF_FALSE; } -void FF_SetDirHashed(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster) { +FF_ERROR FF_HashDir(FF_IOMAN *pIoman, FF_T_UINT32 ulDirCluster) { + // Find most suitable Hash Table to replace! + FF_T_UINT32 i; + FF_HASHCACHE *pHashCache = NULL; + FF_FETCH_CONTEXT FetchContext; + FF_T_UINT8 EntryBuffer[32], ucAttrib; + FF_T_UINT32 ulHash; + + if(FF_DirHashed(pIoman, ulDirCluster)) { + return FF_ERR_NONE; // Don't wastefully re-hash a dir! + } + + //printf("----- Hashing Directory\n"); + + for(i = 0; i < FF_HASH_CACHE_DEPTH; i++) { + if(!pIoman->HashCache[i].ulNumHandles) { + if(!pHashCache) { + pHashCache = &pIoman->HashCache[i]; + } else { + if((pIoman->HashCache[i].ulMisses > pHashCache->ulMisses)) { + pHashCache = &pIoman->HashCache[i]; + } + } + } + } + + if(pHashCache) { + // Clear the hash table! + FF_ClearHashTable(pHashCache->pHashTable); + pHashCache->ulDirCluster = ulDirCluster; + pHashCache->ulMisses = 0; + + // Hash the directory! + + FF_InitEntryFetch(pIoman, ulDirCluster, &FetchContext); + + for(i = 0; i < 0xFFFF; i++) { + if(FF_FetchEntryWithContext(pIoman, i, &FetchContext, EntryBuffer)) { + break; // HT addition + } + ucAttrib = FF_getChar(EntryBuffer, FF_FAT_DIRENT_ATTRIB); + if(FF_getChar(EntryBuffer, 0x00) != 0xE5) { + if(ucAttrib != FF_FAT_ATTR_LFN) { + FF_ProcessShortName((FF_T_INT8 *)EntryBuffer); + if(FF_isEndOfDir(EntryBuffer)) { + // HT uncommented + FF_CleanupEntryFetch(pIoman, &FetchContext); + return FF_ERR_NONE; + } + + // Generate the Hash +#if FF_HASH_FUNCTION == CRC16 + ulHash = FF_GetCRC16(EntryBuffer, strlen((const FF_T_INT8 *) EntryBuffer)); +#elif FF_HASH_FUNCTION == CRC8 + ulHash = FF_GetCRC8(EntryBuffer, strlen((const FF_T_INT8 *) EntryBuffer)); +#endif + FF_SetHash(pHashCache->pHashTable, ulHash); + + } + } + } + + FF_CleanupEntryFetch(pIoman, &FetchContext); + + return FF_ERR_NONE; + } + + return -1; +} + +/*void FF_SetDirHashed(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster) { int i; for(i = 0; i < FF_PATH_CACHE_DEPTH; i++) { if(pIoman->pPartition->PathCache[i].DirCluster == DirCluster) { @@ -1003,27 +1087,273 @@ void FF_SetDirHashed(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster) { return; } } -} +}*/ #endif +FF_ERROR FF_PopulateLongDirent(FF_IOMAN *pIoman, FF_DIRENT *pDirent, FF_T_UINT16 nEntry, FF_FETCH_CONTEXT *pFetchContext) { + // First get the entire name as UTF-16 from the LFN's. + // Then transform into the API's native string format. + + FF_ERROR Error; + FF_T_UINT uiNumLFNs; + FF_T_UINT uiLfnLength = 0; +#ifdef FF_UNICODE_UTF8_SUPPORT + FF_T_UINT i,y; +// FF_T_SINT32 slRetVal; + FF_T_UINT16 nLfnBegin; + FF_T_UINT16 usUtf8Len = 0; +#endif + FF_T_UINT16 myShort; + FF_T_UINT8 ucCheckSum; -FF_T_SINT8 FF_PopulateLongDirent(FF_IOMAN *pIoman, FF_DIRENT *pDirent, FF_T_UINT32 DirCluster, FF_T_UINT16 nEntry) { FF_T_UINT8 EntryBuffer[32]; + //FF_T_UINT16 UTF16Name[FF_MAX_FILENAME]; + +#ifdef FF_UNICODE_SUPPORT + FF_T_WCHAR WCEntryBuffer[32]; + FF_T_WCHAR ShortName[13]; +#else FF_T_INT8 ShortName[13]; +#endif + + Error = FF_FetchEntryWithContext(pIoman, nEntry++, pFetchContext, EntryBuffer); + if(Error) { + return Error; + } + + uiNumLFNs = (FF_T_UINT)(EntryBuffer[0] & ~0x40); + ucCheckSum = FF_getChar(EntryBuffer, FF_FAT_LFN_CHECKSUM); + +#ifdef FF_UNICODE_SUPPORT // UTF-16 Can simply get segments of the UTF-16 sequence going forward + // in the dirents. (I.e. reversed order). + + while(uiNumLFNs) { // Avoid stack intensive use of a UTF-16 buffer. Stream direct to FileName dirent field in correct format. + + // memcopy direct!-UTF-16 support + memcpy(pDirent->FileName + ((uiNumLFNs - 1) * 13) + 0, &EntryBuffer[FF_FAT_LFN_NAME_1], 10); + memcpy(pDirent->FileName + ((uiNumLFNs - 1) * 13) + 5, &EntryBuffer[FF_FAT_LFN_NAME_2], 12); + memcpy(pDirent->FileName + ((uiNumLFNs - 1) * 13) + 11, &EntryBuffer[FF_FAT_LFN_NAME_3], 4); + + + uiLfnLength += 13; + + Error = FF_FetchEntryWithContext(pIoman, nEntry++, pFetchContext, EntryBuffer); + if(Error) { + return Error; + } + uiNumLFNs--; + } + + pDirent->FileName[uiLfnLength] = '\0'; +#endif + +#ifdef FF_UNICODE_UTF8_SUPPORT + // UTF-8 Sequence, we can only convert this from the beginning, must receive entries in reverse. + nLfnBegin = nEntry - 1; + + for(i = 0; i < uiNumLFNs; i++) { + Error = FF_FetchEntryWithContext(pIoman, (nLfnBegin + (uiNumLFNs - 1) - i), pFetchContext, EntryBuffer); + if(Error) { + return Error; + } + + // Now have the first part of the UTF-16 sequence. Stream into a UTF-8 sequence. + for(y = 0; y < 5; y++) { + Error = FF_Utf16ctoUtf8c((FF_T_UINT8 *) &pDirent->FileName[usUtf8Len], (FF_T_UINT16 *) &EntryBuffer[FF_FAT_LFN_NAME_1 + (y*2)], sizeof(pDirent->FileName) - usUtf8Len); + if(Error > 0) { + usUtf8Len += (FF_T_UINT16) Error; + } + } + + for(y = 0; y < 6; y++) { + Error = FF_Utf16ctoUtf8c((FF_T_UINT8 *) &pDirent->FileName[usUtf8Len], (FF_T_UINT16 *) &EntryBuffer[FF_FAT_LFN_NAME_2 + (y*2)], sizeof(pDirent->FileName) - usUtf8Len); + if(Error > 0) { + usUtf8Len += (FF_T_UINT16) Error; + } + } + + for(y = 0; y < 2; y++) { + Error = FF_Utf16ctoUtf8c((FF_T_UINT8 *) &pDirent->FileName[usUtf8Len], (FF_T_UINT16 *) &EntryBuffer[FF_FAT_LFN_NAME_3 + (y*2)], sizeof(pDirent->FileName) - usUtf8Len); + if(Error > 0) { + usUtf8Len += (FF_T_UINT16) Error; + } + } + nEntry++; + } + + pDirent->FileName[usUtf8Len] = '\0'; + + // Put Entry context to correct position. + Error = FF_FetchEntryWithContext(pIoman, nEntry-1, pFetchContext, EntryBuffer); + if(Error) { + return Error; + } + +#endif + +#ifndef FF_UNICODE_SUPPORT +#ifndef FF_UNICODE_UTF8_SUPPORT // No Unicode, simple ASCII. + while(uiNumLFNs) { // Avoid stack intensive use of a UTF-16 buffer. Stream direct to FileName dirent field in correct format. + + for(i = 0; i < 5; i++) { + pDirent->FileName[((uiNumLFNs - 1) * 13) + i] = EntryBuffer[FF_FAT_LFN_NAME_1 + (i*2)]; + } + + for(i = 0; i < 6; i++) { + pDirent->FileName[((uiNumLFNs - 1) * 13) + i + 5] = EntryBuffer[FF_FAT_LFN_NAME_2 + (i*2)]; + } + + for(i = 0; i < 2; i++) { + pDirent->FileName[((uiNumLFNs - 1) * 13) + i + 11] = EntryBuffer[FF_FAT_LFN_NAME_3 + (i*2)]; + } + + uiLfnLength += 13; + + Error = FF_FetchEntryWithContext(pIoman, nEntry++, pFetchContext, EntryBuffer); + if(Error) { + return Error; + } + uiNumLFNs--; + } + + pDirent->FileName[uiLfnLength] = '\0'; + + +#endif +#endif + // Process the Shortname. -- LFN Transformation is now complete. + // Process the ShortName Entry + + // if SHORTNAMES must be included, simple byte copy into shortname buffer. +#if defined(FF_LFN_SUPPORT) && defined(FF_INCLUDE_SHORT_NAME) + memcpy(pDirent->ShortName, EntryBuffer, 11); + pDirent->ShortName[11] = '\0'; + FF_ProcessShortName(pDirent->ShortName); +#endif + +#ifdef FF_UNICODE_SUPPORT + FF_cstrntowcs(WCEntryBuffer, (FF_T_INT8 *) EntryBuffer, 32); + memcpy(ShortName, WCEntryBuffer, 11 * sizeof(FF_T_WCHAR)); +#else + memcpy(ShortName, EntryBuffer, 11); +#endif + FF_ProcessShortName(ShortName); + if(ucCheckSum != FF_CreateChkSum(EntryBuffer)) { +#ifdef FF_UNICODE_SUPPORT + wcscpy(pDirent->FileName, ShortName); +#else + strcpy(pDirent->FileName, ShortName); +#endif + } + + // Finally fill in the other details + myShort = FF_getShort(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_HIGH)); + pDirent->ObjectCluster = (FF_T_UINT32) (myShort << 16); + myShort = FF_getShort(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_LOW)); + pDirent->ObjectCluster |= myShort; + +#ifdef FF_TIME_SUPPORT + // Get the creation Time & Date + FF_GetTime(&pDirent->CreateTime, EntryBuffer, FF_FAT_DIRENT_CREATE_TIME); + FF_GetDate(&pDirent->CreateTime, EntryBuffer, FF_FAT_DIRENT_CREATE_DATE); + // Get the modified Time & Date + FF_GetTime(&pDirent->CreateTime, EntryBuffer, FF_FAT_DIRENT_LASTMOD_TIME); + FF_GetDate(&pDirent->CreateTime, EntryBuffer, FF_FAT_DIRENT_LASTMOD_DATE); + // Get the last accessed Date. + FF_GetDate(&pDirent->AccessedTime, EntryBuffer, FF_FAT_DIRENT_LASTACC_DATE); + pDirent->AccessedTime.Hour = 0; + pDirent->AccessedTime.Minute = 0; + pDirent->AccessedTime.Second = 0; +#endif + + // Get the filesize. + pDirent->Filesize = FF_getLong(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_FILESIZE)); + // Get the attribute. + pDirent->Attrib = FF_getChar(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB)); + + pDirent->CurrentItem = nEntry; + //return x; + return FF_ERR_NONE; +} + +/* +FF_ERROR FF_PopulateLongDirent(FF_IOMAN *pIoman, FF_DIRENT *pDirent, FF_T_UINT16 nEntry, FF_FETCH_CONTEXT *pFetchContext) { + FF_T_UINT8 EntryBuffer[32]; +#ifdef FF_UNICODE_SUPPORT + FF_T_WCHAR UTF16EntryBuffer[32]; + FF_T_WCHAR ShortName[13]; +#if WCHAR_MAX > 0xFFFF + FF_T_UINT16 i,y; +#endif +#else + FF_T_INT8 ShortName[13]; +#ifdef FF_UNICODE_UTF8_SUPPORT + FF_T_SINT32 i, y; +#else + FF_T_UINT16 i, y; +#endif +#endif + +#ifdef FF_UNICODE_UTF8_SUPPORT + FF_T_UINT16 UTF16Name[FF_MAX_FILENAME]; // Read in the entire UTF-16 name into this buffer. + FF_T_UINT16 *UTF16cptr; +#endif FF_T_UINT8 numLFNs; FF_T_UINT8 x; FF_T_UINT8 CheckSum = 0; - FF_T_UINT16 i,y; + FF_T_UINT16 lenlfn = 0; FF_T_UINT16 myShort; + FF_ERROR Error; - FF_FetchEntry(pIoman, DirCluster, nEntry++, EntryBuffer); + Error = FF_FetchEntryWithContext(pIoman, nEntry++, pFetchContext, EntryBuffer); + if(Error) { + return Error; + } + numLFNs = (FF_T_UINT8)(EntryBuffer[0] & ~0x40); // Handle the name CheckSum = FF_getChar(EntryBuffer, FF_FAT_LFN_CHECKSUM); x = numLFNs; while(numLFNs) { + if(numLFNs > 1) { + numLFNs = numLFNs; + } + +#ifdef FF_UNICODE_SUPPORT + // Simply fill the FileName buffer with UTF-16 Filename! +#if WCHAR_MAX <= 0xFFFF // System works in UTF-16 so we can trust it if we just copy the UTF-16 strings directly. + memcpy(pDirent->FileName + ((numLFNs - 1) * 13) + 0, &EntryBuffer[FF_FAT_LFN_NAME_1], (5 * 2)); + memcpy(pDirent->FileName + ((numLFNs - 1) * 13) + 5, &EntryBuffer[FF_FAT_LFN_NAME_2], (6 * 2)); + memcpy(pDirent->FileName + ((numLFNs - 1) * 13) + 11, &EntryBuffer[FF_FAT_LFN_NAME_3], (2 * 2)); + lenlfn += 13; +#else + for(i = 0, y = 0; i < 5; i++, y += 2) { + FF_Utf16ctoUtf32c((FF_T_UINT32 *)&pDirent->FileName[i + ((numLFNs - 1) * 13)], (FF_T_UINT16 *) &EntryBuffer[FF_FAT_LFN_NAME_1 + y]); + //pDirent->FileName[i + ((numLFNs - 1) * 13)] = (FF_T_WCHAR) ((FF_T_WCHAR) EntryBuffer[FF_FAT_LFN_NAME_1 + y] | ((FF_T_WCHAR) EntryBuffer[FF_FAT_LFN_NAME_1 + y + 1] >> 8)); + lenlfn++; + } + for(i = 0, y = 0; i < 6; i++, y += 2) { + FF_Utf16ctoUtf32c((FF_T_UINT32 *)&pDirent->FileName[i + ((numLFNs - 1) * 13) + 5], (FF_T_UINT16 *) &EntryBuffer[FF_FAT_LFN_NAME_2 + y]); + //pDirent->FileName[i + ((numLFNs - 1) * 13) + 5] = (FF_T_WCHAR) ((FF_T_WCHAR) EntryBuffer[FF_FAT_LFN_NAME_2 + y] | ((FF_T_WCHAR) EntryBuffer[FF_FAT_LFN_NAME_2 + y + 1] >> 8)); + lenlfn++; + } + for(i = 0, y = 0; i < 2; i++, y += 2) { + FF_Utf16ctoUtf32c((FF_T_UINT32 *)&pDirent->FileName[i + ((numLFNs - 1) * 13) + 11], (FF_T_UINT16 *) &EntryBuffer[FF_FAT_LFN_NAME_3 + y]); + //pDirent->FileName[i + ((numLFNs - 1) * 13) + 11] = (FF_T_WCHAR) ((FF_T_WCHAR) EntryBuffer[FF_FAT_LFN_NAME_3 + y] | ((FF_T_WCHAR)EntryBuffer[FF_FAT_LFN_NAME_3 + y + 1] >> 8)); + lenlfn++; + } +#endif + // Copy each part of the LFNS +#else +#ifdef FF_UNICODE_UTF8_SUPPORT + memcpy(UTF16Name + ((numLFNs - 1) * 13) + 0, &EntryBuffer[FF_FAT_LFN_NAME_1], (5 * 2)); + memcpy(UTF16Name + ((numLFNs - 1) * 13) + 5, &EntryBuffer[FF_FAT_LFN_NAME_2], (6 * 2)); + memcpy(UTF16Name + ((numLFNs - 1) * 13) + 11, &EntryBuffer[FF_FAT_LFN_NAME_3], (2 * 2)); + lenlfn += 13; +#else + // Attempts to pull ASCII from UTF-8 encoding. for(i = 0, y = 0; i < 5; i++, y += 2) { pDirent->FileName[i + ((numLFNs - 1) * 13)] = EntryBuffer[FF_FAT_LFN_NAME_1 + y]; lenlfn++; @@ -1038,28 +1368,56 @@ FF_T_SINT8 FF_PopulateLongDirent(FF_IOMAN *pIoman, FF_DIRENT *pDirent, FF_T_UINT pDirent->FileName[i + ((numLFNs - 1) * 13) + 11] = EntryBuffer[FF_FAT_LFN_NAME_3 + y]; lenlfn++; } +#endif +#endif - FF_FetchEntry(pIoman, DirCluster, nEntry++, EntryBuffer); + Error = FF_FetchEntryWithContext(pIoman, nEntry++, pFetchContext, EntryBuffer); + if(Error) { + return Error; + } numLFNs--; } +#ifdef FF_UNICODE_UTF8_SUPPORT + UTF16cptr = UTF16Name; + UTF16Name[lenlfn] = '\0'; + i = 0; // Keep tabs of the current char position in the UTF-8 sequence. + while(*UTF16cptr) { + y = FF_Utf16ctoUtf8c((FF_T_UINT8 *)&pDirent->FileName[i], UTF16cptr, (FF_MAX_FILENAME - i)); + i += y; + if(FF_GetUtf16SequenceLen(*UTF16cptr++) == 2) { // IF this is a surrogate, then bump the UTF16 Pointer. + UTF16cptr++; + } + } + pDirent->FileName[i] = '\0'; +#else pDirent->FileName[lenlfn] = '\0'; +#endif // Process the ShortName Entry +#ifdef FF_UNICODE_SUPPORT + FF_cstrntowcs(UTF16EntryBuffer, (FF_T_INT8 *) EntryBuffer, 32); + memcpy(ShortName, UTF16EntryBuffer, 11 * sizeof(FF_T_WCHAR)); +#else memcpy(ShortName, EntryBuffer, 11); +#endif if(CheckSum != FF_CreateChkSum(EntryBuffer)) { FF_ProcessShortName(ShortName); +#ifdef FF_UNICODE_SUPPORT + wcscpy(pDirent->FileName, ShortName); +#else strcpy(pDirent->FileName, ShortName); +#endif } else { FF_ProcessShortName(ShortName); } -#ifdef FF_HASH_TABLE_SUPPORT -#if FF_HASH_FUNCTION == CRC16 - FF_AddDirentHash(pIoman, DirCluster, (FF_T_UINT32)FF_GetCRC16((FF_T_UINT8 *) ShortName, strlen(ShortName))); +#ifdef FF_HASH_TABLE_SUPPORT*/ +/*#if FF_HASH_FUNCTION == CRC16 + FF_AddDirentHash(pIoman, pFetchContext->ulDirCluster, (FF_T_UINT32)FF_GetCRC16((FF_T_UINT8 *) ShortName, strlen(ShortName))); #elif FF_HASH_FUNCTION == CRC8 FF_AddDirentHash(pIoman, DirCluster, (FF_T_UINT32)FF_GetCRC8((FF_T_UINT8 *) ShortName, strlen(ShortName))); -#endif +#endif*//* #endif myShort = FF_getShort(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_HIGH)); @@ -1087,9 +1445,10 @@ FF_T_SINT8 FF_PopulateLongDirent(FF_IOMAN *pIoman, FF_DIRENT *pDirent, FF_T_UINT pDirent->Attrib = FF_getChar(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB)); pDirent->CurrentItem = nEntry; - return x; + //return x; + return FF_ERR_NONE; } - +*/ /** * @public * @brief Find's the first directory entry for the provided path. @@ -1097,6 +1456,22 @@ FF_T_SINT8 FF_PopulateLongDirent(FF_IOMAN *pIoman, FF_DIRENT *pDirent, FF_T_UINT * All values recorded in pDirent must be preserved to and between calls to * FF_FindNext(). * + * If FF_FINDAPI_ALLOW_WILDCARDS is defined, then path will have the following behaviour: + * + * path = "\" - Open the root dir, and iterate through all items. + * path = "\*.c" - Open the root dir, showing only files matching *.c wildcard. + * path = "\sub1\newdir" - Get the DIRENT for the newdir directory in /sub1/ if one exists. + * path = "\sub1\newdir\" - Open the directory /sub1/newdir/ and iterate through all items. + * path = "\sub1\newdir\*.c" - Open the directory /sub1/newdir/ and iterate through all items matching the *.c wildcard. + * + * It is important to distinguish the differences in behaviour between opening a Find operation + * on a path like /sub1 and /sub1/. (/sub1 gets the sub1 dirent from the / dir, whereas /sub/ opens the sub1 dir). + * + * Note, as compatible with other similar APIs, FullFAT also accepts \sub1\* for the same behaviour as + * /sub1/. + * + * For more up-to-date information please see the FullFAT wiki pages. + * * @param pIoman FF_IOMAN object that was created by FF_CreateIOMAN(). * @param pDirent FF_DIRENT object to store the entry information. * @param path String to of the path to the Dir being listed. @@ -1106,60 +1481,78 @@ FF_T_SINT8 FF_PopulateLongDirent(FF_IOMAN *pIoman, FF_DIRENT *pDirent, FF_T_UINT * @return -2 if Dir was not found. * **/ +#ifdef FF_UNICODE_SUPPORT +FF_ERROR FF_FindFirst(FF_IOMAN *pIoman, FF_DIRENT *pDirent, const FF_T_WCHAR *path) { +#else FF_ERROR FF_FindFirst(FF_IOMAN *pIoman, FF_DIRENT *pDirent, const FF_T_INT8 *path) { - FF_T_UINT8 numLFNs; - FF_T_UINT8 EntryBuffer[32]; +#endif +#ifdef FF_UNICODE_SUPPORT + FF_T_UINT16 PathLen = (FF_T_UINT16) wcslen(path); +#else FF_T_UINT16 PathLen = (FF_T_UINT16) strlen(path); +#endif + FF_ERROR Error; + +#ifdef FF_FINDAPI_ALLOW_WILDCARDS + FF_T_UINT16 i = 0; +#ifdef FF_UNICODE_SUPPORT + const FF_T_WCHAR *szWildCard; // Check for a Wild-card. +#else + const FF_T_INT8 *szWildCard; // Check for a Wild-card. +#endif +#endif if(!pIoman) { return FF_ERR_NULL_POINTER; } + // Detect a Wild-Card on the End, or Filename, as apposed to a complete path. +#ifndef FF_FINDAPI_ALLOW_WILDCARDS pDirent->DirCluster = FF_FindDir(pIoman, path, PathLen); // Get the directory cluster, if it exists. +#endif + +#ifdef FF_FINDAPI_ALLOW_WILDCARDS + pDirent->szWildCard[0] = '\0'; // WildCard blank if its not a wildCard. + + szWildCard = &path[PathLen - 1]; + + if(PathLen) { + while(*szWildCard != '\\' && *szWildCard != '/') { // Open the dir of the last token. + i++; + szWildCard--; + if(!(PathLen - i)) { + break; + } + } + } + + pDirent->DirCluster = FF_FindDir(pIoman, path, PathLen - i, &Error); + if(Error) { + return Error; + } + if(pDirent->DirCluster) { + // Valid Dir found, copy the wildCard to filename! +#ifdef FF_UNICODE_SUPPORT + wcsncpy(pDirent->szWildCard, ++szWildCard, FF_MAX_FILENAME); +#else + strncpy(pDirent->szWildCard, ++szWildCard, FF_MAX_FILENAME); +#endif + } +#endif if(pDirent->DirCluster == 0) { return FF_ERR_DIR_INVALID_PATH; } - - for(pDirent->CurrentItem = 0; pDirent->CurrentItem < 0xFFFF; pDirent->CurrentItem += 1) { - if(FF_FetchEntry(pIoman, pDirent->DirCluster, pDirent->CurrentItem, EntryBuffer)) { - return FF_ERR_DIR_END_OF_DIR; - } - if(EntryBuffer[0] != FF_FAT_DELETED) { - if(FF_isEndOfDir(EntryBuffer)){ - return FF_ERR_DIR_END_OF_DIR; - } - pDirent->Attrib = FF_getChar(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB)); - if((pDirent->Attrib & FF_FAT_ATTR_LFN) == FF_FAT_ATTR_LFN) { - // LFN Processing - numLFNs = (FF_T_UINT8)(EntryBuffer[0] & ~0x40); - // Get the shortname and check if it is marked deleted. -#ifdef FF_LFN_SUPPORT - // Fetch the shortname, and get it's checksum, or for a deleted item with - // orphaned LFN entries. - if(FF_FetchEntry(pIoman, pDirent->DirCluster, (pDirent->CurrentItem + numLFNs), EntryBuffer)) { - return FF_ERR_DIR_END_OF_DIR; - } - - if(EntryBuffer[0] != FF_FAT_DELETED) { - FF_PopulateLongDirent(pIoman, pDirent, pDirent->DirCluster, pDirent->CurrentItem); - return FF_ERR_NONE; - } -#else - pDirent->CurrentItem += (numLFNs - 1); -#endif - } else if((pDirent->Attrib & FF_FAT_ATTR_VOLID) == FF_FAT_ATTR_VOLID) { - // Do Nothing - - } else { - FF_PopulateShortDirent(pIoman, pDirent, EntryBuffer); - pDirent->CurrentItem += 1; - return FF_ERR_NONE; - } - } - } - return FF_ERR_DIR_END_OF_DIR; + // Initialise the Fetch Context + Error = FF_InitEntryFetch(pIoman, pDirent->DirCluster, &pDirent->FetchContext); + if(Error) { + return Error; + } + + pDirent->CurrentItem = 0; + + return FF_FindNext(pIoman, pDirent); } /** @@ -1167,16 +1560,17 @@ FF_ERROR FF_FindFirst(FF_IOMAN *pIoman, FF_DIRENT *pDirent, const FF_T_INT8 *pat * @brief Get's the next Entry based on the data recorded in the FF_DIRENT object. * * All values recorded in pDirent must be preserved to and between calls to - * FF_FindNext(). + * FF_FindNext(). Please see @see FF_FindFirst() for find initialisation. * * @param pIoman FF_IOMAN object that was created by FF_CreateIOMAN(). - * @param pDirent FF_DIRENT object to store the entry information. + * @param pDirent FF_DIRENT object to store the entry information. (As initialised by FF_FindFirst()). * * @return FF_ERR_DEVICE_DRIVER_FAILED is device access failed. * **/ FF_ERROR FF_FindNext(FF_IOMAN *pIoman, FF_DIRENT *pDirent) { + FF_ERROR Error; FF_T_UINT8 numLFNs; FF_T_UINT8 EntryBuffer[32]; @@ -1185,11 +1579,14 @@ FF_ERROR FF_FindNext(FF_IOMAN *pIoman, FF_DIRENT *pDirent) { } for(; pDirent->CurrentItem < 0xFFFF; pDirent->CurrentItem += 1) { - if(FF_FetchEntry(pIoman, pDirent->DirCluster, pDirent->CurrentItem, EntryBuffer)) { - return FF_ERR_DIR_END_OF_DIR; + Error = FF_FetchEntryWithContext(pIoman, pDirent->CurrentItem, &pDirent->FetchContext, EntryBuffer); + if(Error) { + FF_CleanupEntryFetch(pIoman, &pDirent->FetchContext); + return Error; } if(EntryBuffer[0] != FF_FAT_DELETED) { if(FF_isEndOfDir(EntryBuffer)){ + FF_CleanupEntryFetch(pIoman, &pDirent->FetchContext); return FF_ERR_DIR_END_OF_DIR; } pDirent->Attrib = FF_getChar(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB)); @@ -1200,13 +1597,41 @@ FF_ERROR FF_FindNext(FF_IOMAN *pIoman, FF_DIRENT *pDirent) { #ifdef FF_LFN_SUPPORT // Fetch the shortname, and get it's checksum, or for a deleted item with // orphaned LFN entries. - if(FF_FetchEntry(pIoman, pDirent->DirCluster, (pDirent->CurrentItem + numLFNs), EntryBuffer)) { - return FF_ERR_DIR_END_OF_DIR; + Error = FF_FetchEntryWithContext(pIoman, (pDirent->CurrentItem + numLFNs), &pDirent->FetchContext, EntryBuffer); + if(Error) { + FF_CleanupEntryFetch(pIoman, &pDirent->FetchContext); + return Error; } if(EntryBuffer[0] != FF_FAT_DELETED) { - FF_PopulateLongDirent(pIoman, pDirent, pDirent->DirCluster, pDirent->CurrentItem); + Error = FF_PopulateLongDirent(pIoman, pDirent, pDirent->CurrentItem, &pDirent->FetchContext); + if(Error) { + FF_CleanupEntryFetch(pIoman, &pDirent->FetchContext); + return Error; + } +#ifdef FF_INCLUDE_SHORT_NAME + pDirent->Attrib |= FF_FAT_ATTR_IS_LFN; +#endif + +#ifdef FF_FINDAPI_ALLOW_WILDCARDS +#ifdef FF_UNICODE_SUPPORT + if(wcscmp(pDirent->szWildCard, L"")) { +#else + if(strcmp(pDirent->szWildCard, "")) { +#endif + if(FF_wildcompare(pDirent->szWildCard, pDirent->FileName)) { + FF_CleanupEntryFetch(pIoman, &pDirent->FetchContext); + return FF_ERR_NONE; + } + pDirent->CurrentItem -= 1; + } else { + FF_CleanupEntryFetch(pIoman, &pDirent->FetchContext); + return FF_ERR_NONE; + } +#else + FF_CleanupEntryFetch(pIoman, &pDirent->FetchContext); return FF_ERR_NONE; +#endif } #else pDirent->CurrentItem += (numLFNs - 1); @@ -1216,11 +1641,37 @@ FF_ERROR FF_FindNext(FF_IOMAN *pIoman, FF_DIRENT *pDirent) { } else { FF_PopulateShortDirent(pIoman, pDirent, EntryBuffer); +#if defined(FF_SHORTNAME_CASE) + // Apply NT/XP+ bits to get correct case + FF_CaseShortName(pDirent->FileName, FF_getChar(EntryBuffer, FF_FAT_CASE_OFFS)); +#endif +#ifdef FF_FINDAPI_ALLOW_WILDCARDS +#ifdef FF_UNICODE_SUPPORT + if(wcscmp(pDirent->szWildCard, L"")) { +#else + if(strcmp(pDirent->szWildCard, "")) { +#endif + if(FF_wildcompare(pDirent->szWildCard, pDirent->FileName)) { + FF_CleanupEntryFetch(pIoman, &pDirent->FetchContext); + pDirent->CurrentItem += 1; + return FF_ERR_NONE; + } + } else { + FF_CleanupEntryFetch(pIoman, &pDirent->FetchContext); + pDirent->CurrentItem += 1; + return FF_ERR_NONE; + } +#else + + FF_CleanupEntryFetch(pIoman, &pDirent->FetchContext); pDirent->CurrentItem += 1; return FF_ERR_NONE; +#endif } } } + + FF_CleanupEntryFetch(pIoman, &pDirent->FetchContext); return FF_ERR_DIR_END_OF_DIR; } @@ -1234,30 +1685,55 @@ FF_T_SINT8 FF_RewindFind(FF_IOMAN *pIoman, FF_DIRENT *pDirent) { return 0; } +/* + Returns >= 0 for a free dirent entry. + Returns < 0 with and Error code if anything goes wrong. +*/ +static FF_T_SINT32 FF_FindFreeDirent(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT16 Sequential) { -FF_T_SINT32 FF_FindFreeDirent(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT16 Sequential) { + FF_T_UINT8 EntryBuffer[32]; + FF_T_UINT16 i = 0; + FF_T_UINT16 nEntry; + FF_ERROR Error; + FF_T_UINT32 DirLength; + FF_FETCH_CONTEXT FetchContext; - FF_T_UINT8 EntryBuffer[32]; - FF_T_UINT16 i = 0; - FF_T_UINT16 nEntry; - FF_T_SINT8 RetVal; - FF_T_UINT32 DirLength; - FF_T_UINT32 iEndOfChain; + Error = FF_InitEntryFetch(pIoman, DirCluster, &FetchContext); + if(Error) { + return Error; + } for(nEntry = 0; nEntry < 0xFFFF; nEntry++) { - if(FF_FetchEntry(pIoman, DirCluster, nEntry, EntryBuffer) == FF_ERR_DIR_END_OF_DIR) { - RetVal = FF_ExtendDirectory(pIoman, DirCluster); - if(RetVal != FF_ERR_NONE) { - return RetVal; + Error = FF_FetchEntryWithContext(pIoman, nEntry, &FetchContext, EntryBuffer); + if(Error == FF_ERR_DIR_END_OF_DIR) { + + Error = FF_ExtendDirectory(pIoman, DirCluster); + FF_CleanupEntryFetch(pIoman, &FetchContext); + + if(Error) { + return Error; } + return nEntry; + } else { + if(Error) { + FF_CleanupEntryFetch(pIoman, &FetchContext); + return Error; + } } if(FF_isEndOfDir(EntryBuffer)) { // If its the end of the Dir, then FreeDirents from here. // Check Dir is long enough! - DirLength = FF_GetChainLength(pIoman, DirCluster, &iEndOfChain); + DirLength = FetchContext.ulChainLength;//FF_GetChainLength(pIoman, DirCluster, &iEndOfChain); if((nEntry + Sequential) > (FF_T_UINT16)(((pIoman->pPartition->SectorsPerCluster * pIoman->pPartition->BlkSize) * DirLength) / 32)) { - FF_ExtendDirectory(pIoman, DirCluster); + Error = FF_ExtendDirectory(pIoman, DirCluster); } + + FF_CleanupEntryFetch(pIoman, &FetchContext); + + if(Error) { + return Error; + } + return nEntry; } if(EntryBuffer[0] == 0xE5) { @@ -1267,36 +1743,48 @@ FF_T_SINT32 FF_FindFreeDirent(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UIN } if(i == Sequential) { + FF_CleanupEntryFetch(pIoman, &FetchContext); return (nEntry - (Sequential - 1));// Return the beginning entry in the sequential sequence. } } - return FF_ERR_DIR_DIRECTORY_FULL; + FF_CleanupEntryFetch(pIoman, &FetchContext); + + return FF_ERR_DIR_DIRECTORY_FULL; } -FF_T_SINT8 FF_PutEntry(FF_IOMAN *pIoman, FF_T_UINT16 Entry, FF_T_UINT32 DirCluster, FF_DIRENT *pDirent) { +FF_ERROR FF_PutEntry(FF_IOMAN *pIoman, FF_T_UINT16 Entry, FF_T_UINT32 DirCluster, FF_DIRENT *pDirent) { FF_BUFFER *pBuffer; + FF_ERROR Error; FF_T_UINT32 itemLBA; FF_T_UINT32 clusterNum = FF_getClusterChainNumber (pIoman, Entry, (FF_T_UINT16)32); FF_T_UINT32 relItem = FF_getMinorBlockEntry (pIoman, Entry, (FF_T_UINT16)32); - FF_T_UINT32 clusterAddress = FF_TraverseFAT(pIoman, DirCluster, clusterNum); + FF_T_UINT32 clusterAddress = FF_TraverseFAT(pIoman, DirCluster, clusterNum, &Error); + + if(Error) { + return Error; + } itemLBA = FF_Cluster2LBA(pIoman, clusterAddress) + FF_getMajorBlockNumber(pIoman, Entry, (FF_T_UINT16)32); itemLBA = FF_getRealLBA (pIoman, itemLBA) + FF_getMinorBlockNumber(pIoman, relItem, (FF_T_UINT16)32); pBuffer = FF_GetBuffer(pIoman, itemLBA, FF_MODE_WRITE); { + if(!pBuffer) { + return FF_ERR_DEVICE_DRIVER_FAILED; + } // Modify the Entry! //memcpy((pBuffer->pBuffer + (32*relItem)), pDirent->FileName, 11); - FF_putChar(pBuffer->pBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB + (32 * relItem)), pDirent->Attrib); - FF_putShort(pBuffer->pBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_HIGH + (32 * relItem)), (FF_T_UINT16)(pDirent->ObjectCluster >> 16)); - FF_putShort(pBuffer->pBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_LOW + (32 * relItem)), (FF_T_UINT16)(pDirent->ObjectCluster)); - FF_putLong(pBuffer->pBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_FILESIZE + (32 * relItem)), pDirent->Filesize); + relItem *= 32; + FF_putChar(pBuffer->pBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB + relItem), pDirent->Attrib); + FF_putShort(pBuffer->pBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_HIGH + relItem), (FF_T_UINT16)(pDirent->ObjectCluster >> 16)); + FF_putShort(pBuffer->pBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_LOW + relItem), (FF_T_UINT16)(pDirent->ObjectCluster)); + FF_putLong(pBuffer->pBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_FILESIZE + relItem), pDirent->Filesize); #ifdef FF_TIME_SUPPORT - FF_PlaceDate((pBuffer->pBuffer + (32 * relItem)), FF_FAT_DIRENT_LASTACC_DATE); // Last accessed date. + FF_PlaceDate((pBuffer->pBuffer + relItem), FF_FAT_DIRENT_LASTACC_DATE); // Last accessed date. #endif } FF_ReleaseBuffer(pIoman, pBuffer); @@ -1304,143 +1792,200 @@ FF_T_SINT8 FF_PutEntry(FF_IOMAN *pIoman, FF_T_UINT16 Entry, FF_T_UINT32 DirClust return 0; } +FF_T_BOOL FF_ValidShortChar (FF_T_INT8 Chr) +{ + return (Chr >= 'A' && Chr <= 'Z') || +#if defined(FF_SHORTNAME_CASE) + (Chr >= 'a' && Chr <= 'z') || // lower-case can be stored using NT/XP attribute +#endif + (Chr >= '0' && Chr <= '9') || + strchr ("$%-_@~`!(){}^#&", Chr) != NULL; +} -/*static FF_T_BOOL FF_isShortName(const FF_T_UINT8 *Name, FF_T_UINT16 StrLen) { - FF_T_UINT16 i; - for(i = 0; i < StrLen; i++) { - if(Name[i] == '.') { - i--; - } - } - if(i < 11) { - return FF_TRUE; - } - return FF_FALSE; -}*/ +FF_T_BOOL FF_ValidLongChar (FF_T_INT8 Chr) +{ + return Chr >= 0x20 && strchr ("/\\:*?\"<>|", Chr) == NULL; +} +#ifdef FF_UNICODE_SUPPORT +FF_T_SINT8 FF_CreateShortName(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_WCHAR *ShortName, FF_T_WCHAR *LongName) { +#else FF_T_SINT8 FF_CreateShortName(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *ShortName, FF_T_INT8 *LongName) { - FF_T_UINT16 i,x,y; - FF_T_INT8 TempName[FF_MAX_FILENAME]; +#endif + FF_T_UINT8 caseAttrib = 0; +#if defined(FF_SHORTNAME_CASE) + FF_T_UINT8 testAttrib = FF_FAT_CASE_ATTR_BASE; +#endif + + FF_T_UINT16 i,x,y,last_dot; + FF_T_UINT16 first_tilde = 6; +#ifdef FF_UNICODE_SUPPORT + FF_T_WCHAR MyShortName[13]; +#else FF_T_INT8 MyShortName[13]; - FF_T_UINT16 NameLen; - FF_T_BOOL FitsShort = FF_FALSE; +#endif + FF_T_UINT16 NameLen; + FF_T_BOOL FitsShort = FF_TRUE; FF_DIRENT MyDir; + FF_T_BOOL found; //FF_T_SINT8 RetVal = 0; FF_T_INT8 NumberBuf[6]; - // Create a Short Name - strncpy(TempName, LongName, FF_MAX_FILENAME); - NameLen = (FF_T_UINT16) strlen(TempName); - FF_toupper(TempName, NameLen); + FF_ERROR Error; - // Initialise Shortname - - for(i = 0; i < 11; i++) { - ShortName[i] = 0x20; - } +#ifdef FF_UNICODE_SUPPORT + NameLen = (FF_T_UINT16) wcslen(LongName); +#else + NameLen = (FF_T_UINT16) strlen(LongName); +#endif // Does LongName fit a shortname? - for(i = 0, x = 0; i < NameLen; i++) { - if(TempName[i] != '.') { + for(i = 0, x = 0, last_dot = NameLen; i < NameLen; i++) { + if(LongName[i] != '.') { x++; - } - } - - if(x <= 11) { - //FitsShort = FF_TRUE; - } - - // Main part of the name - for(i = 0, x = 0; i < 8; i++, x++) { - if(i == 0 && TempName[x] == '.') { - i--; } else { - if(TempName[x] == '.') { - break; - } else if(TempName[x] == ' ') { - i--; - } else { - ShortName[i] = TempName[x]; - if(ShortName[i] == 0x00) { - ShortName[i] = 0x20; - } - } - } - } - - for(i = NameLen; i > x; i--) { - if(TempName[i] == '.') { - break; + last_dot = i; } } - if(TempName[i] == '.') { - x = i + 1; - for(i = 0; i < 3; i++) { - if(x < NameLen) { - ShortName[8 + i] = TempName[x++]; + if (NameLen > 12 || NameLen-x > 1 || NameLen-last_dot > 4 || last_dot > 8) { + FitsShort = FF_FALSE; + } + + for(i = 0, x = 0; i < 11; x++) { + FF_T_INT8 ch = (FF_T_INT8) LongName[x]; + if (!ch) + break; + if (x == last_dot) { + while (i < 8) + ShortName[i++] = 0x20; +#if defined(FF_SHORTNAME_CASE) + testAttrib = FF_FAT_CASE_ATTR_EXT; +#endif + } else { + if (i == 8) { + x = last_dot; + ch = (FF_T_INT8) LongName[x]; + if (ch) + ch = (FF_T_INT8) LongName[++x]; +#if defined(FF_SHORTNAME_CASE) + testAttrib = FF_FAT_CASE_ATTR_EXT; +#endif } + if (!FF_ValidShortChar (ch)) { + FitsShort = FF_FALSE; + continue; + } + if (ch >= 'a' && ch <= 'z') { + ch -= 0x20; +#if defined(FF_SHORTNAME_CASE) + if (testAttrib) + caseAttrib |= testAttrib; + else + FitsShort = FF_FALSE; // We had capital: does not fit + } else if (ch >= 'A' && ch <= 'Z') { + if (caseAttrib & testAttrib) + FitsShort = FF_FALSE; // We had lower-case: does not fit + testAttrib = 0; +#endif + } + ShortName[i++] = ch; } } + while (i < 11) + ShortName[i++] = 0x20; + if (last_dot < first_tilde) + first_tilde = last_dot; + if (NameLen < first_tilde) // Names like "Abc" will become "~Abc" + first_tilde = NameLen; // Tail : memcpy(MyShortName, ShortName, 11); FF_ProcessShortName(MyShortName); - - if(!FF_FindEntryInDir(pIoman, DirCluster, MyShortName, 0x00, &MyDir) && FitsShort) { - return 0; - } else { - if(FitsShort) { - return FF_ERR_DIR_OBJECT_EXISTS; - } - for(i = 1; i < 0x0000FFFF; i++) { // Max Number of Entries in a DIR! - sprintf(NumberBuf, "%d", i); - NameLen = (FF_T_UINT16) strlen(NumberBuf); - x = 7 - NameLen; - ShortName[x++] = '~'; - for(y = 0; y < NameLen; y++) { - ShortName[x+y] = NumberBuf[y]; - } - memcpy(MyShortName, ShortName, 11); - FF_ProcessShortName(MyShortName); - if(!FF_ShortNameExists(pIoman, DirCluster, MyShortName)) { - return 0; - } - } - // Add a tail and special number until we're happy :D + found = (FF_T_BOOL) FF_FindEntryInDir(pIoman, DirCluster, MyShortName, 0x00, &MyDir, &Error); +#ifdef Hein_Tibosch + if (verboseLevel >= 1) logPrintf ("Long Name: %-14.14s Short '%s' (%s) Fit '%d' Found %d\n", LongName, ShortName, MyShortName, FitsShort, found); +#endif + if(FitsShort && !found) { + return caseAttrib | 0x01; } + if(FitsShort) { + return FF_ERR_DIR_OBJECT_EXISTS; + } + for(i = 1; i < 0x0000FFFF; i++) { // Max Number of Entries in a DIR! + sprintf(NumberBuf, "%d", i); + NameLen = (FF_T_UINT16) strlen(NumberBuf); + x = 7 - NameLen; + if (x > first_tilde) + x = first_tilde; + ShortName[x++] = '~'; + for(y = 0; y < NameLen; y++) { + ShortName[x+y] = NumberBuf[y]; + } + memcpy(MyShortName, ShortName, 11); + FF_ProcessShortName(MyShortName); + found = FF_ShortNameExists(pIoman, DirCluster, MyShortName, &Error); +#ifdef Hein_Tibosch + if (verboseLevel >= 1) logPrintf ("Long Name: %-14.14s Short '%s' (%s) Fit '%d' Found %d\n", LongName, ShortName, MyShortName, FitsShort, found); +#endif + if(!found) { +#ifdef FF_HASH_CACHE +#if FF_HASH_FUNCTION == CRC16 + FF_AddDirentHash(pIoman, DirCluster, (FF_T_UINT32) FF_GetCRC16((FF_T_UINT8*)MyShortName, strlen(MyShortName))); +#elif FF_HASH_FUNCTION == CRC8 + FF_AddDirentHash(pIoman, DirCluster, (FF_T_UINT32) FF_GetCRC8((FF_T_UINT8*)MyShortName, strlen(MyShortName))); +#endif +#endif + return 0; + } + } + // Add a tail and special number until we're happy :D return FF_ERR_DIR_DIRECTORY_FULL; } + + #ifdef FF_LFN_SUPPORT -static FF_T_SINT8 FF_CreateLFNEntry(FF_T_UINT8 *EntryBuffer, FF_T_INT8 *Name, FF_T_UINT8 NameLen, FF_T_UINT8 nLFN, FF_T_UINT8 CheckSum) { +static FF_T_SINT8 FF_CreateLFNEntry(FF_T_UINT8 *EntryBuffer, FF_T_UINT16 *Name, FF_T_UINT uiNameLen, FF_T_UINT uiLFN, FF_T_UINT8 CheckSum) { - FF_T_UINT8 i, x; + FF_T_UINT i, x; memset(EntryBuffer, 0, 32); - FF_putChar(EntryBuffer, FF_FAT_LFN_ORD, (FF_T_UINT8) ((nLFN & ~0x40))); + FF_putChar(EntryBuffer, FF_FAT_LFN_ORD, (FF_T_UINT8) ((uiLFN & ~0x40))); FF_putChar(EntryBuffer, FF_FAT_DIRENT_ATTRIB, (FF_T_UINT8) FF_FAT_ATTR_LFN); FF_putChar(EntryBuffer, FF_FAT_LFN_CHECKSUM, (FF_T_UINT8) CheckSum); // Name_1 for(i = 0, x = 0; i < 5; i++, x += 2) { - if(i < NameLen) { - EntryBuffer[FF_FAT_LFN_NAME_1 + x] = Name[i]; - } else if (i == NameLen) { - EntryBuffer[FF_FAT_LFN_NAME_1 + x] = '\0'; - }else { - EntryBuffer[FF_FAT_LFN_NAME_1 + x] = 0xFF; - EntryBuffer[FF_FAT_LFN_NAME_1 + x + 1] = 0xFF; + if(i < uiNameLen) + { + memcpy(&EntryBuffer[FF_FAT_LFN_NAME_1 + x], &Name[i], sizeof(FF_T_UINT16)); + //bobtntfullfat *((FF_T_UINT16 *) &EntryBuffer[FF_FAT_LFN_NAME_1 + x]) = Name[i]; } + else + if (i == uiNameLen) + { + EntryBuffer[FF_FAT_LFN_NAME_1 + x] = '\0'; + EntryBuffer[FF_FAT_LFN_NAME_1 + x + 1] = '\0'; + } + else + { + EntryBuffer[FF_FAT_LFN_NAME_1 + x] = 0xFF; + EntryBuffer[FF_FAT_LFN_NAME_1 + x + 1] = 0xFF; + } } // Name_2 for(i = 0, x = 0; i < 6; i++, x += 2) { - if((i + 5) < NameLen) { - EntryBuffer[FF_FAT_LFN_NAME_2 + x] = Name[i+5]; - } else if ((i + 5) == NameLen) { - EntryBuffer[FF_FAT_LFN_NAME_2 + x] = '\0'; + if((i + 5) < uiNameLen) + { + memcpy(&EntryBuffer[FF_FAT_LFN_NAME_2 + x], &Name[i+5], sizeof(FF_T_UINT16)); + //EntryBuffer[FF_FAT_LFN_NAME_2 + x] = Name[i+5]; + //bobtntfullfat *((FF_T_UINT16 *) &EntryBuffer[FF_FAT_LFN_NAME_2 + x]) = Name[i+5]; + } else if ((i + 5) == uiNameLen) { + EntryBuffer[FF_FAT_LFN_NAME_2 + x] = '\0'; + EntryBuffer[FF_FAT_LFN_NAME_2 + x + 1] = '\0'; }else { EntryBuffer[FF_FAT_LFN_NAME_2 + x] = 0xFF; EntryBuffer[FF_FAT_LFN_NAME_2 + x + 1] = 0xFF; @@ -1449,10 +1994,14 @@ static FF_T_SINT8 FF_CreateLFNEntry(FF_T_UINT8 *EntryBuffer, FF_T_INT8 *Name, FF // Name_3 for(i = 0, x = 0; i < 2; i++, x += 2) { - if((i + 11) < NameLen) { - EntryBuffer[FF_FAT_LFN_NAME_3 + x] = Name[i+11]; - } else if ((i + 11) == NameLen) { - EntryBuffer[FF_FAT_LFN_NAME_3 + x] = '\0'; + if((i + 11) < uiNameLen) + { + memcpy(&EntryBuffer[FF_FAT_LFN_NAME_3 + x], &Name[i+11], sizeof(FF_T_UINT16)); + //EntryBuffer[FF_FAT_LFN_NAME_3 + x] = Name[i+11]; + //bobtntfullfat *((FF_T_UINT16 *) &EntryBuffer[FF_FAT_LFN_NAME_3 + x]) = Name[i+11]; + } else if ((i + 11) == uiNameLen) { + EntryBuffer[FF_FAT_LFN_NAME_3 + x] = '\0'; + EntryBuffer[FF_FAT_LFN_NAME_3 + x + 1] = '\0'; }else { EntryBuffer[FF_FAT_LFN_NAME_3 + x] = 0xFF; EntryBuffer[FF_FAT_LFN_NAME_3 + x + 1] = 0xFF; @@ -1461,13 +2010,26 @@ static FF_T_SINT8 FF_CreateLFNEntry(FF_T_UINT8 *EntryBuffer, FF_T_INT8 *Name, FF return FF_ERR_NONE; } +#endif -static FF_T_SINT8 FF_CreateLFNs(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *Name, FF_T_UINT8 CheckSum, FF_T_UINT16 nEntry) { +/* +#ifdef FF_UNICODE_SUPPORT +static FF_ERROR FF_CreateLFNs(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_WCHAR *Name, FF_T_UINT8 CheckSum, FF_T_UINT16 nEntry) { +#else +static FF_ERROR FF_CreateLFNs(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *Name, FF_T_UINT8 CheckSum, FF_T_UINT16 nEntry) { +#endif FF_T_UINT8 EntryBuffer[32]; +#ifdef FF_UNICODE_SUPPORT + FF_T_UINT16 NameLen = (FF_T_UINT16) wcslen(Name); +#else FF_T_UINT16 NameLen = (FF_T_UINT16) strlen(Name); +#endif FF_T_UINT8 NumLFNs = (FF_T_UINT8) (NameLen / 13); FF_T_UINT8 i; FF_T_UINT8 EndPos = (NameLen % 13); + FF_ERROR Error; + + FF_FETCH_CONTEXT FetchContext; if(EndPos) { NumLFNs ++; @@ -1475,6 +2037,11 @@ static FF_T_SINT8 FF_CreateLFNs(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_I EndPos = 13; } + Error = FF_InitEntryFetch(pIoman, DirCluster, &FetchContext); + if(Error) { + return Error; + } + for(i = NumLFNs; i > 0; i--) { if(i == NumLFNs) { FF_CreateLFNEntry(EntryBuffer, (Name + (13 * (i - 1))), EndPos, i, CheckSum); @@ -1482,16 +2049,143 @@ static FF_T_SINT8 FF_CreateLFNs(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_I } else { FF_CreateLFNEntry(EntryBuffer, (Name + (13 * (i - 1))), 13, i, CheckSum); } - FF_PushEntry(pIoman, DirCluster, nEntry + (NumLFNs - i), EntryBuffer); + + Error = FF_PushEntryWithContext(pIoman, nEntry + (NumLFNs - i), &FetchContext, EntryBuffer); + if(Error) { + FF_CleanupEntryFetch(pIoman, &FetchContext); + return Error; + } } + FF_CleanupEntryFetch(pIoman, &FetchContext); + return FF_ERR_NONE; } #endif +*/ -FF_T_SINT8 FF_ExtendDirectory(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster) { + +#ifdef FF_UNICODE_SUPPORT +static FF_ERROR FF_CreateLFNs(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_WCHAR *Name, FF_T_UINT8 CheckSum, FF_T_UINT16 nEntry) { +#else +static FF_ERROR FF_CreateLFNs(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *Name, FF_T_UINT8 CheckSum, FF_T_UINT16 nEntry) { +#endif + FF_ERROR Error; + FF_T_UINT uiNumLFNs; + FF_T_UINT uiEndPos; + FF_T_UINT i,y; + +#ifdef FF_UNICODE_UTF8_SUPPORT + FF_T_SINT32 slRetVal; +#endif + +#ifndef FF_UNICODE_SUPPORT +#ifndef FF_UNICODE_UTF8_SUPPORT + FF_T_UINT16 *pUtf16; +#endif +#endif + + FF_FETCH_CONTEXT FetchContext; + + FF_T_UINT8 EntryBuffer[32]; + FF_T_UINT16 usUtf16Name[FF_MAX_FILENAME + 1]; + + +#ifdef FF_UNICODE_SUPPORT +#if WCHAR_MAX <= 0xFFFF + y = wcslen(Name); + if(y > FF_MAX_FILENAME) { + return FF_ERR_DIR_NAME_TOO_LONG; + } + wcsncpy(usUtf16Name, Name, FF_MAX_FILENAME); +#else + i = 0; + y = 0; + while(Name[i]) { + FF_Utf32ctoUtf16c(&usUtf16Name[y], (FF_T_UINT32) Name[i], FF_MAX_FILENAME - i); + y += FF_GetUtf16SequenceLen(usUtf16Name[y]); + i++; + if(y > FF_MAX_FILENAME) { + return FF_ERR_DIR_NAME_TOO_LONG; + } + } +#endif +#endif + + // Convert the name into UTF-16 format. +#ifdef FF_UNICODE_UTF8_SUPPORT + // Simply convert the UTF8 to UTF16 and be done with it. + i = 0; + y = 0; + while(Name[i]) { + slRetVal = FF_Utf8ctoUtf16c(&usUtf16Name[y], (FF_T_UINT8 *)&Name[i], FF_MAX_FILENAME - i); + if(slRetVal > 0) { + i += slRetVal; + } else { + break; // No more space in the UTF-16 buffer, simply truncate for safety. + } + y += FF_GetUtf16SequenceLen(usUtf16Name[y]); + if(y > FF_MAX_FILENAME) { + return FF_ERR_DIR_NAME_TOO_LONG; + } + } +#else +#ifndef FF_UNICODE_SUPPORT + i = 0; + y = strlen(Name); + if(y > FF_MAX_FILENAME) { + return FF_ERR_DIR_NAME_TOO_LONG; + } + pUtf16 = usUtf16Name; + while(Name[i]) { + usUtf16Name[i] = (FF_T_UINT16) Name[i]; + i++; + } +#endif +#endif + + // Whole name is now in a valid UTF-16 format. Lets go make thos LFN's. + // i should at this point be the length of the name. + + uiNumLFNs = y / 13; // Number of LFNs is the total number of UTF-16 units, divided by 13 (13 units per LFN). + uiEndPos = y % 13; // The ending position in an LFN, of the last LFN UTF-16 charachter. + + if(uiEndPos) { + uiNumLFNs++; + } else { + uiEndPos = 13; + } + + Error = FF_InitEntryFetch(pIoman, DirCluster, &FetchContext); + if(Error) { + return Error; + } + + // After this point, i is no longer the length of the Filename in UTF-16 units. + for(i = uiNumLFNs; i > 0; i--) { + if(i == uiNumLFNs) { + FF_CreateLFNEntry(EntryBuffer, (usUtf16Name + (13 * (i - 1))), uiEndPos, i, CheckSum); + EntryBuffer[0] |= 0x40; + } else { + FF_CreateLFNEntry(EntryBuffer, (usUtf16Name + (13 * (i - 1))), 13, i, CheckSum); + } + + Error = FF_PushEntryWithContext(pIoman, nEntry + (uiNumLFNs - i), &FetchContext, EntryBuffer); + if(Error) { + FF_CleanupEntryFetch(pIoman, &FetchContext); + return Error; + } + } + + FF_CleanupEntryFetch(pIoman, &FetchContext); + + return FF_ERR_NONE; +} + +FF_ERROR FF_ExtendDirectory(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster) { FF_T_UINT32 CurrentCluster; FF_T_UINT32 NextCluster; + FF_ERROR Error; if(pIoman->pPartition->Type != FF_T_FAT32) { if(DirCluster == pIoman->pPartition->RootDirCluster) { @@ -1500,7 +2194,10 @@ FF_T_SINT8 FF_ExtendDirectory(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster) { } if(!pIoman->pPartition->FreeClusterCount) { - pIoman->pPartition->FreeClusterCount = FF_CountFreeClusters(pIoman); + pIoman->pPartition->FreeClusterCount = FF_CountFreeClusters(pIoman, &Error); + if(Error) { + return Error; + } if(pIoman->pPartition->FreeClusterCount == 0) { return FF_ERR_FAT_NO_FREE_CLUSTERS; } @@ -1508,20 +2205,52 @@ FF_T_SINT8 FF_ExtendDirectory(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster) { FF_lockFAT(pIoman); { - CurrentCluster = FF_FindEndOfChain(pIoman, DirCluster); - NextCluster = FF_FindFreeCluster(pIoman); - FF_putFatEntry(pIoman, CurrentCluster, NextCluster); - FF_putFatEntry(pIoman, NextCluster, 0xFFFFFFFF); + CurrentCluster = FF_FindEndOfChain(pIoman, DirCluster, &Error); + if(Error) { + FF_unlockFAT(pIoman); + return Error; + } + + NextCluster = FF_FindFreeCluster(pIoman, &Error); + if(Error) { + FF_unlockFAT(pIoman); + return Error; + } + + Error = FF_putFatEntry(pIoman, CurrentCluster, NextCluster); + if(Error) { + FF_unlockFAT(pIoman); + return Error; + } + + Error = FF_putFatEntry(pIoman, NextCluster, 0xFFFFFFFF); + if(Error) { + FF_unlockFAT(pIoman); + return Error; + } } FF_unlockFAT(pIoman); - FF_ClearCluster(pIoman, NextCluster); - FF_DecreaseFreeClusters(pIoman, 1); + Error = FF_ClearCluster(pIoman, NextCluster); + if(Error) { + FF_unlockFAT(pIoman); + return Error; + } + + Error = FF_DecreaseFreeClusters(pIoman, 1); + if(Error) { + FF_unlockFAT(pIoman); + return Error; + } return FF_ERR_NONE; } -static void FF_MakeNameCompliant(FF_T_INT8 *Name) { +#ifdef FF_UNICODE_SUPPORT +static void FF_MakeNameCompliant(FF_T_WCHAR *Name) { +#else +static void FF_MakeNameCompliant(FF_T_UINT8 *Name) { +#endif if((FF_T_UINT8) Name[0] == 0xE5) { // Support Japanese KANJI symbol. Name[0] = 0x05; @@ -1531,7 +2260,7 @@ static void FF_MakeNameCompliant(FF_T_INT8 *Name) { if(*Name < 0x20 || *Name == 0x7F || *Name == 0x22 || *Name == 0x7C) { // Leave all extended chars as they are. *Name = '_'; } - if(*Name >= 0x2A && *Name <= 0x2F && *Name != 0x2B && *Name != 0x2E) { + if(*Name >= 0x2A && *Name <= 0x2F && *Name != 0x2B && *Name != 0x2E && *Name != 0x2D) { *Name = '_'; } if(*Name >= 0x3A && *Name <= 0x3F) { @@ -1544,23 +2273,43 @@ static void FF_MakeNameCompliant(FF_T_INT8 *Name) { } } -FF_T_SINT8 FF_CreateDirent(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_DIRENT *pDirent) { +FF_ERROR FF_CreateDirent(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_DIRENT *pDirent) { FF_T_UINT8 EntryBuffer[32]; +#ifdef FF_UNICODE_SUPPORT + FF_T_UINT16 NameLen = (FF_T_UINT16) wcslen(pDirent->FileName); +#else FF_T_UINT16 NameLen = (FF_T_UINT16) strlen(pDirent->FileName); +#endif FF_T_UINT8 numLFNs = (FF_T_UINT8) (NameLen / 13); FF_T_SINT32 FreeEntry; - FF_T_SINT8 RetVal = 0; + FF_ERROR RetVal = FF_ERR_NONE; FF_T_UINT8 Entries; + + FF_FETCH_CONTEXT FetchContext; + #ifdef FF_LFN_SUPPORT FF_T_UINT8 CheckSum; #endif +#ifdef FF_UNICODE_SUPPORT + FF_T_WCHAR UTF16EntryBuffer[32]; +#if WCHAR_MAX > 0xFFFF + // Check that the filename won't exceed the max LFN length if converted to UTF-16. + /*if(FF_Utf32GetUtf16Len((FF_T_UINT32 *) pDirent->FileName) > FF_MAX_FILENAME) { + return FF_ERR_UNICODE_CONVERSION_EXCEEDED; + }*/ +#endif + +#endif + +#ifdef FF_UNICODE_SUPPORT FF_MakeNameCompliant(pDirent->FileName); // Ensure we don't break the Dir tables. +#else + FF_MakeNameCompliant((FF_T_UINT8 *)pDirent->FileName); // Ensure we don't break the Dir tables. +#endif memset(EntryBuffer, 0, 32); - - if(NameLen % 13) { numLFNs ++; } @@ -1576,10 +2325,18 @@ FF_T_SINT8 FF_CreateDirent(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_DIRENT * FF_lockDIR(pIoman); { if((FreeEntry = FF_FindFreeDirent(pIoman, DirCluster, Entries)) >= 0) { +#ifdef FF_UNICODE_SUPPORT + //FF_cstrntowcs(UTF16EntryBuffer, (FF_T_INT8 *) EntryBuffer, 32); + RetVal = FF_CreateShortName(pIoman, DirCluster, UTF16EntryBuffer, pDirent->FileName); +#else RetVal = FF_CreateShortName(pIoman, DirCluster, (FF_T_INT8 *) EntryBuffer, pDirent->FileName); +#endif - if(!RetVal) { + //if(!RetVal) { #ifdef FF_LFN_SUPPORT +#ifdef FF_UNICODE_SUPPORT + FF_wcsntocstr((FF_T_INT8 *) EntryBuffer, UTF16EntryBuffer, 11); +#endif CheckSum = FF_CreateChkSum(EntryBuffer); FF_CreateLFNs(pIoman, DirCluster, pDirent->FileName, CheckSum, (FF_T_UINT16) FreeEntry); #else @@ -1598,10 +2355,24 @@ FF_T_SINT8 FF_CreateDirent(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_DIRENT * FF_putShort(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_LOW), (FF_T_UINT16)(pDirent->ObjectCluster)); FF_putLong(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_FILESIZE), pDirent->Filesize); - FF_PushEntry(pIoman, DirCluster, (FF_T_UINT16) (FreeEntry + numLFNs), EntryBuffer); - } + RetVal = FF_InitEntryFetch(pIoman, DirCluster, &FetchContext); + if(RetVal) { + FF_unlockDIR(pIoman); + return RetVal; + } + RetVal = FF_PushEntryWithContext(pIoman, (FF_T_UINT16) (FreeEntry + numLFNs), &FetchContext, EntryBuffer); + FF_CleanupEntryFetch(pIoman, &FetchContext); + if(RetVal) { + FF_unlockDIR(pIoman); + return RetVal; + } + /*} else { + FF_unlockDIR(pIoman); + return RetVal; + }*/ }else { - RetVal = (FF_T_SINT8) FreeEntry; + FF_unlockDIR(pIoman); + return FreeEntry; } } FF_unlockDIR(pIoman); @@ -1614,19 +2385,36 @@ FF_T_SINT8 FF_CreateDirent(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_DIRENT * pDirent->CurrentItem = (FF_T_UINT16) (FreeEntry + numLFNs); } - return 0; + return FF_ERR_NONE; } -FF_T_UINT32 FF_CreateFile(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *FileName, FF_DIRENT *pDirent) { - FF_DIRENT MyFile; + +#ifdef FF_UNICODE_SUPPORT +FF_T_UINT32 FF_CreateFile(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_WCHAR *FileName, FF_DIRENT *pDirent, FF_ERROR *pError) { +#else +FF_T_UINT32 FF_CreateFile(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *FileName, FF_DIRENT *pDirent, FF_ERROR *pError) { +#endif + FF_DIRENT MyFile; + *pError = FF_ERR_NONE; +#ifdef FF_UNICODE_SUPPORT + wcsncpy(MyFile.FileName, FileName, FF_MAX_FILENAME); +#else strncpy(MyFile.FileName, FileName, FF_MAX_FILENAME); +#endif MyFile.Attrib = 0x00; MyFile.Filesize = 0; - MyFile.ObjectCluster = FF_CreateClusterChain(pIoman); + MyFile.ObjectCluster = FF_CreateClusterChain(pIoman, pError); + if(*pError) { + FF_UnlinkClusterChain(pIoman, MyFile.ObjectCluster, 0); + FF_FlushCache(pIoman); + return 0; + } MyFile.CurrentItem = 0; - if(FF_CreateDirent(pIoman, DirCluster, &MyFile)) { + *pError = FF_CreateDirent(pIoman, DirCluster, &MyFile); + + if(*pError) { FF_UnlinkClusterChain(pIoman, MyFile.ObjectCluster, 0); FF_FlushCache(pIoman); return 0; @@ -1653,20 +2441,34 @@ FF_T_UINT32 FF_CreateFile(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *F * @return FF_ERR_DIR_INVALID_PATH * @return FF_ERR_NONE on success. **/ +#ifdef FF_UNICODE_SUPPORT +FF_ERROR FF_MkDir(FF_IOMAN *pIoman, const FF_T_WCHAR *Path) { +#else FF_ERROR FF_MkDir(FF_IOMAN *pIoman, const FF_T_INT8 *Path) { +#endif FF_DIRENT MyDir; FF_T_UINT32 DirCluster; +#ifdef FF_UNICODE_SUPPORT + FF_T_WCHAR DirName[FF_MAX_FILENAME]; +#else FF_T_INT8 DirName[FF_MAX_FILENAME]; +#endif FF_T_UINT8 EntryBuffer[32]; FF_T_UINT32 DotDotCluster; FF_T_UINT16 i; - FF_T_SINT8 RetVal = 0; + FF_ERROR Error = FF_ERR_NONE; + + FF_FETCH_CONTEXT FetchContext; if(!pIoman) { return FF_ERR_NULL_POINTER; } +#ifdef FF_UNICODE_SUPPORT + i = (FF_T_UINT16) wcslen(Path); +#else i = (FF_T_UINT16) strlen(Path); +#endif while(i != 0) { if(Path[i] == '\\' || Path[i] == '/') { @@ -1675,35 +2477,60 @@ FF_ERROR FF_MkDir(FF_IOMAN *pIoman, const FF_T_INT8 *Path) { i--; } +#ifdef FF_UNICODE_SUPPORT + wcsncpy(DirName, (Path + i + 1), FF_MAX_FILENAME); +#else strncpy(DirName, (Path + i + 1), FF_MAX_FILENAME); +#endif if(i == 0) { i = 1; } - DirCluster = FF_FindDir(pIoman, Path, i); + DirCluster = FF_FindDir(pIoman, Path, i, &Error); + + if(Error) { + return Error; + } if(DirCluster) { - - /*if(!FF_FindEntry(pIoman, DirCluster, DirName, &MyDir, FF_TRUE)) { - return FF_ERR_DIR_OBJECT_EXISTS; - }*/ - if(FF_FindEntryInDir(pIoman, DirCluster, DirName, 0x00, &MyDir)) { + if(FF_FindEntryInDir(pIoman, DirCluster, DirName, 0x00, &MyDir, &Error)) { return FF_ERR_DIR_OBJECT_EXISTS; } + if(Error && Error != FF_ERR_DIR_END_OF_DIR) { + return Error; + } + +#ifdef FF_UNICODE_SUPPORT + wcsncpy(MyDir.FileName, DirName, FF_MAX_FILENAME); +#else strncpy(MyDir.FileName, DirName, FF_MAX_FILENAME); +#endif MyDir.Filesize = 0; MyDir.Attrib = FF_FAT_ATTR_DIR; - MyDir.ObjectCluster = FF_CreateClusterChain(pIoman); - FF_ClearCluster(pIoman, MyDir.ObjectCluster); + MyDir.ObjectCluster = FF_CreateClusterChain(pIoman, &Error); + if(Error) { + return Error; + } + if(MyDir.ObjectCluster) { + Error = FF_ClearCluster(pIoman, MyDir.ObjectCluster); + if(Error) { + FF_UnlinkClusterChain(pIoman, MyDir.ObjectCluster, 0); + FF_FlushCache(pIoman); + return Error; + } + } else { + // Couldn't allocate any space for the dir! + return FF_ERR_DIR_EXTEND_FAILED; + } - RetVal = FF_CreateDirent(pIoman, DirCluster, &MyDir); + Error = FF_CreateDirent(pIoman, DirCluster, &MyDir); - if(RetVal) { + if(Error) { FF_UnlinkClusterChain(pIoman, MyDir.ObjectCluster, 0); FF_FlushCache(pIoman); - return RetVal; + return Error; } memset(EntryBuffer, 0, 32); @@ -1716,7 +2543,20 @@ FF_ERROR FF_MkDir(FF_IOMAN *pIoman, const FF_T_INT8 *Path) { FF_putShort(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_LOW), (FF_T_UINT16) MyDir.ObjectCluster); FF_putLong(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_FILESIZE), 0); - FF_PushEntry(pIoman, MyDir.ObjectCluster, 0, EntryBuffer); + Error = FF_InitEntryFetch(pIoman, MyDir.ObjectCluster, &FetchContext); + if(Error) { + FF_UnlinkClusterChain(pIoman, MyDir.ObjectCluster, 0); + FF_FlushCache(pIoman); + return Error; + } + + Error = FF_PushEntryWithContext(pIoman, 0, &FetchContext, EntryBuffer); + if(Error) { + FF_UnlinkClusterChain(pIoman, MyDir.ObjectCluster, 0); + FF_FlushCache(pIoman); + FF_CleanupEntryFetch(pIoman, &FetchContext); + return Error; + } memset(EntryBuffer, 0, 32); EntryBuffer[0] = '.'; @@ -1736,8 +2576,16 @@ FF_ERROR FF_MkDir(FF_IOMAN *pIoman, const FF_T_INT8 *Path) { FF_putShort(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_LOW), (FF_T_UINT16) DotDotCluster); FF_putLong(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_FILESIZE), 0); - FF_PushEntry(pIoman, MyDir.ObjectCluster, 1, EntryBuffer); - + //FF_PushEntry(pIoman, MyDir.ObjectCluster, 1, EntryBuffer); + Error = FF_PushEntryWithContext(pIoman, 1, &FetchContext, EntryBuffer); + if(Error) { + FF_UnlinkClusterChain(pIoman, MyDir.ObjectCluster, 0); + FF_FlushCache(pIoman); + FF_CleanupEntryFetch(pIoman, &FetchContext); + return Error; + } + FF_CleanupEntryFetch(pIoman, &FetchContext); + FF_FlushCache(pIoman); // Ensure dir was flushed to the disk! return FF_ERR_NONE; @@ -1748,25 +2596,32 @@ FF_ERROR FF_MkDir(FF_IOMAN *pIoman, const FF_T_INT8 *Path) { -void FF_RmLFNs(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT16 DirEntry) { +FF_ERROR FF_RmLFNs(FF_IOMAN *pIoman, FF_T_UINT16 usDirEntry, FF_FETCH_CONTEXT *pContext) { + FF_ERROR Error; FF_T_UINT8 EntryBuffer[32]; - DirEntry--; + usDirEntry--; do { - FF_FetchEntry(pIoman, DirCluster, DirEntry, EntryBuffer); + Error = FF_FetchEntryWithContext(pIoman, usDirEntry, pContext, EntryBuffer); + if(Error) { + return Error; + } if(FF_getChar(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB)) == FF_FAT_ATTR_LFN) { FF_putChar(EntryBuffer, (FF_T_UINT16) 0, (FF_T_UINT8) 0xE5); - FF_PushEntry(pIoman, DirCluster, DirEntry, EntryBuffer); + Error = FF_PushEntryWithContext(pIoman, usDirEntry, pContext, EntryBuffer); + if(Error) { + return Error; + } } - if(DirEntry == 0) { + if(usDirEntry == 0) { break; } - DirEntry--; + usDirEntry--; }while(FF_getChar(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB)) == FF_FAT_ATTR_LFN); + return FF_ERR_NONE; } - diff --git a/lib/3rdparty/fullfat/ff_dir.h b/lib/3rdparty/fullfat/ff_dir.h deleted file mode 100644 index 7415eac06e6..00000000000 --- a/lib/3rdparty/fullfat/ff_dir.h +++ /dev/null @@ -1,105 +0,0 @@ -/***************************************************************************** - * FullFAT - High Performance, Thread-Safe Embedded FAT File-System * - * Copyright (C) 2009 James Walmsley (james@worm.me.uk) * - * * - * This program is free software: you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation, either version 3 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program. If not, see . * - * * - * IMPORTANT NOTICE: * - * ================= * - * Alternative Licensing is available directly from the Copyright holder, * - * (James Walmsley). For more information consult LICENSING.TXT to obtain * - * a Commercial license. * - * * - * See RESTRICTIONS.TXT for extra restrictions on the use of FullFAT. * - * * - * Removing the above notice is illegal and will invalidate this license. * - ***************************************************************************** - * See http://worm.me.uk/fullfat for more information. * - * Or http://fullfat.googlecode.com/ for latest releases and the wiki. * - *****************************************************************************/ - -/** - * @file ff_dir.h - * @author James Walmsley - * @ingroup DIR - **/ -#ifndef _FF_DIR_H_ -#define _FF_DIR_H_ - -#include "ff_types.h" -#include "ff_config.h" -#include "ff_error.h" -#include "ff_ioman.h" -#include "ff_blk.h" -#include "ff_fat.h" -#include "fat.h" -#include "ff_memory.h" -#include "ff_time.h" -#include "ff_hash.h" -#include "ff_crc.h" -#include "ff_file.h" -#include - -typedef struct { - FF_T_INT8 FileName[FF_MAX_FILENAME]; - FF_T_UINT8 Attrib; - FF_T_UINT32 Filesize; - FF_T_UINT32 ObjectCluster; - -#ifdef FF_TIME_SUPPORT - FF_SYSTEMTIME CreateTime; ///< Date and Time Created. - FF_SYSTEMTIME ModifiedTime; ///< Date and Time Modified. - FF_SYSTEMTIME AccessedTime; ///< Date of Last Access. -#endif - - //---- Book Keeping for FF_Find Functions - FF_T_UINT16 CurrentItem; - FF_T_UINT32 DirCluster; - FF_T_UINT32 CurrentCluster; - FF_T_UINT32 AddrCurrentCluster; - //FF_T_UINT8 NumLFNs; -} FF_DIRENT; - - FF_ERROR FF_GetEntry (FF_IOMAN *pIoman, FF_T_UINT16 nEntry, FF_T_UINT32 DirCluster, FF_DIRENT *pDirent); - FF_T_SINT8 FF_PutEntry (FF_IOMAN *pIoman, FF_T_UINT16 Entry, FF_T_UINT32 DirCluster, FF_DIRENT *pDirent); - FF_T_SINT8 FF_FindEntry (FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *Name, FF_DIRENT *pDirent, FF_T_BOOL LFNs); - FF_ERROR FF_FindFirst (FF_IOMAN *pIoman, FF_DIRENT *pDirent, const FF_T_INT8 *path); - FF_ERROR FF_FindNext (FF_IOMAN *pIoman, FF_DIRENT *pDirent); - void FF_PopulateShortDirent(FF_IOMAN *pIoman, FF_DIRENT *pDirent, FF_T_UINT8 *EntryBuffer); - FF_T_SINT8 FF_PopulateLongDirent(FF_IOMAN *pIoman, FF_DIRENT *pDirent, FF_T_UINT32 DirCluster, FF_T_UINT16 nEntry); - FF_T_SINT8 FF_FetchEntry (FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT16 nEntry, FF_T_UINT8 *buffer); - FF_T_SINT8 FF_PushEntry (FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT16 nEntry, FF_T_UINT8 *buffer); - FF_T_BOOL FF_isEndOfDir (FF_T_UINT8 *EntryBuffer); - FF_T_SINT8 FF_FindNextInDir(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_DIRENT *pDirent); - FF_T_UINT32 FF_FindEntryInDir(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *name, FF_T_UINT8 pa_Attrib, FF_DIRENT *pDirent); - FF_T_SINT8 FF_CreateShortName(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *ShortName, FF_T_INT8 *LongName); - -void FF_lockDIR (FF_IOMAN *pIoman); -void FF_unlockDIR (FF_IOMAN *pIoman); -FF_T_UINT32 FF_CreateFile(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *FileName, FF_DIRENT *pDirent); -FF_ERROR FF_MkDir(FF_IOMAN *pIoman, const FF_T_INT8 *Path); -FF_T_SINT8 FF_CreateDirent(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_DIRENT *pDirent); -FF_T_SINT8 FF_ExtendDirectory(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster); -FF_T_UINT32 FF_FindDir(FF_IOMAN *pIoman, const FF_T_INT8 *path, FF_T_UINT16 pathLen); - - -FF_T_BOOL FF_CheckDirentHash(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT32 nHash); -FF_T_BOOL FF_DirHashed(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster); -FF_ERROR FF_AddDirentHash(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT32 nHash); -void FF_SetDirHashed(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster); - -void FF_RmLFNs(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT16 DirEntry); - -#endif - diff --git a/lib/3rdparty/fullfat/ff_error.c b/lib/3rdparty/fullfat/ff_error.c index 483bf964ce3..787c8769aaa 100644 --- a/lib/3rdparty/fullfat/ff_error.c +++ b/lib/3rdparty/fullfat/ff_error.c @@ -56,7 +56,7 @@ const struct _FFERRTAB {"Not enough memory (malloc() returned NULL).", FF_ERR_NOT_ENOUGH_MEMORY}, {"Device Driver returned a FATAL error!.", FF_ERR_DEVICE_DRIVER_FAILED}, {"The blocksize is not 512 multiple.", FF_ERR_IOMAN_BAD_BLKSIZE}, - {"The provided memory size, is not a multiple of the blocksize.", FF_ERR_IOMAN_BAD_MEMSIZE}, + {"The memory size, is not a multiple of the blocksize. (Atleast 2 Blocks).", FF_ERR_IOMAN_BAD_MEMSIZE}, {"Device is already registered, use FF_UnregisterBlkDevice() first.", FF_ERR_IOMAN_DEV_ALREADY_REGD}, {"No mountable partition was found on the specified device.", FF_ERR_IOMAN_NO_MOUNTABLE_PARTITION}, {"The format of the MBR was unrecognised.", FF_ERR_IOMAN_INVALID_FORMAT}, @@ -65,6 +65,7 @@ const struct _FFERRTAB {"Cannot register device. (BlkSize not a multiple of 512).", FF_ERR_IOMAN_DEV_INVALID_BLKSIZE}, {"Cannot unregister device, a partition is still mounted.", FF_ERR_IOMAN_PARTITION_MOUNTED}, {"Cannot unmount the partition while there are active FILE handles.", FF_ERR_IOMAN_ACTIVE_HANDLES}, + {"The GPT partition header appears to be corrupt, refusing to mount.", FF_ERR_IOMAN_GPT_HEADER_CORRUPT}, {"Cannot open the file, file already in use.", FF_ERR_FILE_ALREADY_OPEN}, {"The specified file could not be found.", FF_ERR_FILE_NOT_FOUND}, {"Cannot open a Directory.", FF_ERR_FILE_OBJECT_IS_A_DIR}, @@ -84,6 +85,9 @@ const struct _FFERRTAB {"Source file was not found.", FF_ERR_FILE_SOURCE_NOT_FOUND}, {"Destination path (dir) was not found.", FF_ERR_FILE_DIR_NOT_FOUND}, {"Failed to create the directory Entry.", FF_ERR_FILE_COULD_NOT_CREATE_DIRENT}, + {"Not enough free disk space to complete the disk transaction.", FF_ERR_IOMAN_NOT_ENOUGH_FREE_SPACE}, + {"Attempted to Read a sector out of bounds.", FF_ERR_IOMAN_OUT_OF_BOUNDS_READ}, + {"Attempted to Write a sector out of bounds.", FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE}, }; /** diff --git a/lib/3rdparty/fullfat/ff_fat.c b/lib/3rdparty/fullfat/ff_fat.c index 1cbd420ffad..fb5ac824033 100644 --- a/lib/3rdparty/fullfat/ff_fat.c +++ b/lib/3rdparty/fullfat/ff_fat.c @@ -110,7 +110,7 @@ FF_T_UINT32 FF_LBA2Cluster(FF_IOMAN *pIoman, FF_T_UINT32 Address) { /** * @private **/ -FF_T_SINT32 FF_getFatEntry(FF_IOMAN *pIoman, FF_T_UINT32 nCluster) { +FF_T_UINT32 FF_getFatEntry(FF_IOMAN *pIoman, FF_T_UINT32 nCluster, FF_ERROR *pError) { FF_BUFFER *pBuffer; FF_T_UINT32 FatOffset; @@ -136,19 +136,20 @@ FF_T_SINT32 FF_getFatEntry(FF_IOMAN *pIoman, FF_T_UINT32 nCluster) { FatSectorEntry = FatOffset % pIoman->pPartition->BlkSize; LBAadjust = (FF_T_UINT8) (FatSectorEntry / pIoman->BlkSize); - relClusterEntry = (FF_T_UINT16) (FatSectorEntry % pIoman->BlkSize); + relClusterEntry = (FF_T_UINT32) (FatSectorEntry % pIoman->BlkSize); FatSector = FF_getRealLBA(pIoman, FatSector); #ifdef FF_FAT12_SUPPORT if(pIoman->pPartition->Type == FF_T_FAT12) { - if(relClusterEntry == (pIoman->BlkSize - 1)) { + if(relClusterEntry == (FF_T_UINT32)(pIoman->BlkSize - 1)) { // Fat Entry SPANS a Sector! // First Buffer get the last Byte in buffer (first byte of our address)! pBuffer = FF_GetBuffer(pIoman, FatSector + LBAadjust, FF_MODE_READ); { if(!pBuffer) { - return FF_ERR_DEVICE_DRIVER_FAILED; + *pError = FF_ERR_DEVICE_DRIVER_FAILED; + return 0; } F12short[0] = FF_getChar(pBuffer->pBuffer, (FF_T_UINT16)(pIoman->BlkSize - 1)); } @@ -157,7 +158,8 @@ FF_T_SINT32 FF_getFatEntry(FF_IOMAN *pIoman, FF_T_UINT32 nCluster) { pBuffer = FF_GetBuffer(pIoman, FatSector + LBAadjust + 1, FF_MODE_READ); { if(!pBuffer) { - return FF_ERR_DEVICE_DRIVER_FAILED; + *pError = FF_ERR_DEVICE_DRIVER_FAILED; + return 0; } F12short[1] = FF_getChar(pBuffer->pBuffer, 0); } @@ -176,7 +178,8 @@ FF_T_SINT32 FF_getFatEntry(FF_IOMAN *pIoman, FF_T_UINT32 nCluster) { pBuffer = FF_GetBuffer(pIoman, FatSector + LBAadjust, FF_MODE_READ); { if(!pBuffer) { - return FF_ERR_DEVICE_DRIVER_FAILED; + *pError = FF_ERR_DEVICE_DRIVER_FAILED; + return 0; } switch(pIoman->pPartition->Type) { @@ -208,11 +211,10 @@ FF_T_SINT32 FF_getFatEntry(FF_IOMAN *pIoman, FF_T_UINT32 nCluster) { return (FF_T_SINT32) FatEntry; } -FF_T_SINT8 FF_ClearCluster(FF_IOMAN *pIoman, FF_T_UINT32 nCluster) { +FF_ERROR FF_ClearCluster(FF_IOMAN *pIoman, FF_T_UINT32 nCluster) { FF_BUFFER *pBuffer; FF_T_UINT16 i; FF_T_UINT32 BaseLBA; - FF_T_SINT8 RetVal = 0; BaseLBA = FF_Cluster2LBA(pIoman, nCluster); BaseLBA = FF_getRealLBA(pIoman, BaseLBA); @@ -220,16 +222,15 @@ FF_T_SINT8 FF_ClearCluster(FF_IOMAN *pIoman, FF_T_UINT32 nCluster) { for(i = 0; i < pIoman->pPartition->SectorsPerCluster; i++) { pBuffer = FF_GetBuffer(pIoman, BaseLBA++, FF_MODE_WRITE); { - if(pBuffer) { - memset(pBuffer->pBuffer, 0x00, 512); - } else { - RetVal = FF_ERR_DEVICE_DRIVER_FAILED; + if(!pBuffer) { + return FF_ERR_DEVICE_DRIVER_FAILED; } + memset(pBuffer->pBuffer, 0x00, 512); } FF_ReleaseBuffer(pIoman, pBuffer); } - return RetVal; + return FF_ERR_NONE; } /** @@ -240,17 +241,19 @@ FF_T_SINT8 FF_ClearCluster(FF_IOMAN *pIoman, FF_T_UINT32 nCluster) { * @param Start Cluster address of the first cluster in the chain. * @param Count Number of Cluster in the chain, * - * @return FF_TRUE if it is an end of chain, otherwise FF_FALSE. + * * **/ -FF_T_UINT32 FF_TraverseFAT(FF_IOMAN *pIoman, FF_T_UINT32 Start, FF_T_UINT32 Count) { +FF_T_UINT32 FF_TraverseFAT(FF_IOMAN *pIoman, FF_T_UINT32 Start, FF_T_UINT32 Count, FF_ERROR *pError) { FF_T_UINT32 i; FF_T_UINT32 fatEntry = Start, currentCluster = Start; + *pError = FF_ERR_NONE; + for(i = 0; i < Count; i++) { - fatEntry = FF_getFatEntry(pIoman, currentCluster); - if(fatEntry == (FF_T_UINT32) FF_ERR_DEVICE_DRIVER_FAILED) { + fatEntry = FF_getFatEntry(pIoman, currentCluster, pError); + if(*pError) { return 0; } @@ -264,13 +267,14 @@ FF_T_UINT32 FF_TraverseFAT(FF_IOMAN *pIoman, FF_T_UINT32 Start, FF_T_UINT32 Coun return fatEntry; } -FF_T_UINT32 FF_FindEndOfChain(FF_IOMAN *pIoman, FF_T_UINT32 Start) { +FF_T_UINT32 FF_FindEndOfChain(FF_IOMAN *pIoman, FF_T_UINT32 Start, FF_ERROR *pError) { FF_T_UINT32 fatEntry = Start, currentCluster = Start; + *pError = FF_ERR_NONE; while(!FF_isEndOfChain(pIoman, fatEntry)) { - fatEntry = FF_getFatEntry(pIoman, currentCluster); - if(fatEntry == (FF_T_UINT32) FF_ERR_DEVICE_DRIVER_FAILED) { + fatEntry = FF_getFatEntry(pIoman, currentCluster, pError); + if(*pError) { return 0; } @@ -325,7 +329,7 @@ FF_T_BOOL FF_isEndOfChain(FF_IOMAN *pIoman, FF_T_UINT32 fatEntry) { * @param nCluster Cluster Number to be modified. * @param Value The Value to store. **/ -FF_T_SINT8 FF_putFatEntry(FF_IOMAN *pIoman, FF_T_UINT32 nCluster, FF_T_UINT32 Value) { +FF_ERROR FF_putFatEntry(FF_IOMAN *pIoman, FF_T_UINT32 nCluster, FF_T_UINT32 Value) { FF_BUFFER *pBuffer; FF_T_UINT32 FatOffset; @@ -333,7 +337,7 @@ FF_T_SINT8 FF_putFatEntry(FF_IOMAN *pIoman, FF_T_UINT32 nCluster, FF_T_UINT32 Va FF_T_UINT32 FatSectorEntry; FF_T_UINT32 FatEntry; FF_T_UINT8 LBAadjust; - FF_T_UINT16 relClusterEntry; + FF_T_UINT32 relClusterEntry; #ifdef FF_FAT12_SUPPORT FF_T_UINT8 F12short[2]; // For FAT12 FAT Table Across sector boundary traversal. #endif @@ -350,13 +354,13 @@ FF_T_SINT8 FF_putFatEntry(FF_IOMAN *pIoman, FF_T_UINT32 nCluster, FF_T_UINT32 Va FatSectorEntry = FatOffset % pIoman->pPartition->BlkSize; LBAadjust = (FF_T_UINT8) (FatSectorEntry / pIoman->BlkSize); - relClusterEntry = (FF_T_UINT16)(FatSectorEntry % pIoman->BlkSize); + relClusterEntry = (FF_T_UINT32)(FatSectorEntry % pIoman->BlkSize); FatSector = FF_getRealLBA(pIoman, FatSector); #ifdef FF_FAT12_SUPPORT if(pIoman->pPartition->Type == FF_T_FAT12) { - if(relClusterEntry == (FF_T_UINT16) (pIoman->BlkSize - 1)) { + if(relClusterEntry == (FF_T_UINT32)(pIoman->BlkSize - 1)) { // Fat Entry SPANS a Sector! // First Buffer get the last Byte in buffer (first byte of our address)! pBuffer = FF_GetBuffer(pIoman, FatSector + LBAadjust, FF_MODE_READ); @@ -439,7 +443,7 @@ FF_T_SINT8 FF_putFatEntry(FF_IOMAN *pIoman, FF_T_UINT32 nCluster, FF_T_UINT32 Va } FF_ReleaseBuffer(pIoman, pBuffer); - return 0; + return FF_ERR_NONE; } @@ -454,12 +458,17 @@ FF_T_SINT8 FF_putFatEntry(FF_IOMAN *pIoman, FF_T_UINT32 nCluster, FF_T_UINT32 Va * @return 0 on error. **/ #ifdef FF_FAT12_SUPPORT -FF_T_UINT32 FF_FindFreeClusterOLD(FF_IOMAN *pIoman) { +static FF_T_UINT32 FF_FindFreeClusterOLD(FF_IOMAN *pIoman, FF_ERROR *pError) { FF_T_UINT32 nCluster; FF_T_UINT32 fatEntry; + *pError = FF_ERR_NONE; + for(nCluster = pIoman->pPartition->LastFreeCluster; nCluster < pIoman->pPartition->NumClusters; nCluster++) { - fatEntry = FF_getFatEntry(pIoman, nCluster); + fatEntry = FF_getFatEntry(pIoman, nCluster, pError); + if(*pError) { + return 0; + } if(fatEntry == 0x00000000) { pIoman->pPartition->LastFreeCluster = nCluster; return nCluster; @@ -469,7 +478,7 @@ FF_T_UINT32 FF_FindFreeClusterOLD(FF_IOMAN *pIoman) { } #endif -FF_T_UINT32 FF_FindFreeCluster(FF_IOMAN *pIoman) { +FF_T_UINT32 FF_FindFreeCluster(FF_IOMAN *pIoman, FF_ERROR *pError) { FF_BUFFER *pBuffer; FF_T_UINT32 i, x, nCluster = pIoman->pPartition->LastFreeCluster; FF_T_UINT32 FatOffset; @@ -478,9 +487,11 @@ FF_T_UINT32 FF_FindFreeCluster(FF_IOMAN *pIoman) { FF_T_UINT32 EntriesPerSector; FF_T_UINT32 FatEntry = 1; + *pError = FF_ERR_NONE; + #ifdef FF_FAT12_SUPPORT if(pIoman->pPartition->Type == FF_T_FAT12) { // FAT12 tables are too small to optimise, and would make it very complicated! - return FF_FindFreeClusterOLD(pIoman); + return FF_FindFreeClusterOLD(pIoman, pError); } #endif @@ -491,12 +502,22 @@ FF_T_UINT32 FF_FindFreeCluster(FF_IOMAN *pIoman) { EntriesPerSector = pIoman->BlkSize / 2; FatOffset = nCluster * 2; } + + // HT addition: don't use non-existing clusters + if (nCluster >= pIoman->pPartition->NumClusters) { + *pError = FF_ERR_FAT_NO_FREE_CLUSTERS; + return 0; + } FatSector = (FatOffset / pIoman->pPartition->BlkSize); for(i = FatSector; i < pIoman->pPartition->SectorsPerFAT; i++) { pBuffer = FF_GetBuffer(pIoman, pIoman->pPartition->FatBeginLBA + i, FF_MODE_READ); { + if(!pBuffer) { + *pError = FF_ERR_DEVICE_DRIVER_FAILED; + return 0; + } for(x = nCluster % EntriesPerSector; x < EntriesPerSector; x++) { if(pIoman->pPartition->Type == FF_T_FAT32) { FatOffset = x * 4; @@ -528,24 +549,54 @@ FF_T_UINT32 FF_FindFreeCluster(FF_IOMAN *pIoman) { * @private * @brief Create's a Cluster Chain **/ -FF_T_UINT32 FF_CreateClusterChain(FF_IOMAN *pIoman) { +FF_T_UINT32 FF_CreateClusterChain(FF_IOMAN *pIoman, FF_ERROR *pError) { FF_T_UINT32 iStartCluster; + FF_ERROR Error; + *pError = FF_ERR_NONE; + FF_lockFAT(pIoman); { - iStartCluster = FF_FindFreeCluster(pIoman); - FF_putFatEntry(pIoman, iStartCluster, 0xFFFFFFFF); // Mark the cluster as EOC + iStartCluster = FF_FindFreeCluster(pIoman, &Error); + if(Error) { + *pError = Error; + FF_unlockFAT(pIoman); + return 0; + } + + if(iStartCluster) { + Error = FF_putFatEntry(pIoman, iStartCluster, 0xFFFFFFFF); // Mark the cluster as End-Of-Chain + if(Error) { + *pError = Error; + FF_unlockFAT(pIoman); + return 0; + } + } } FF_unlockFAT(pIoman); + + if(iStartCluster) { + Error = FF_DecreaseFreeClusters(pIoman, 1); + if(Error) { + *pError = Error; + return 0; + } + } + return iStartCluster; } -FF_T_UINT32 FF_GetChainLength(FF_IOMAN *pIoman, FF_T_UINT32 pa_nStartCluster, FF_T_UINT32 *piEndOfChain) { +FF_T_UINT32 FF_GetChainLength(FF_IOMAN *pIoman, FF_T_UINT32 pa_nStartCluster, FF_T_UINT32 *piEndOfChain, FF_ERROR *pError) { FF_T_UINT32 iLength = 0; + + *pError = FF_ERR_NONE; FF_lockFAT(pIoman); { while(!FF_isEndOfChain(pIoman, pa_nStartCluster)) { - pa_nStartCluster = FF_getFatEntry(pIoman, pa_nStartCluster); + pa_nStartCluster = FF_getFatEntry(pIoman, pa_nStartCluster, pError); + if(*pError) { + return 0; + } iLength++; } if(piEndOfChain) { @@ -607,11 +658,13 @@ FF_T_UINT32 FF_ExtendClusterChain(FF_IOMAN *pIoman, FF_T_UINT32 StartCluster, FF * @return -1 If the device driver failed to provide access. * **/ -FF_T_SINT8 FF_UnlinkClusterChain(FF_IOMAN *pIoman, FF_T_UINT32 StartCluster, FF_T_UINT16 Count) { +FF_ERROR FF_UnlinkClusterChain(FF_IOMAN *pIoman, FF_T_UINT32 StartCluster, FF_T_UINT16 Count) { FF_T_UINT32 fatEntry; FF_T_UINT32 currentCluster, chainLength = 0; FF_T_UINT32 iLen = 0; + FF_T_UINT32 lastFree = StartCluster; /* HT addition : reset LastFreeCluster */ + FF_ERROR Error; fatEntry = StartCluster; @@ -620,16 +673,35 @@ FF_T_SINT8 FF_UnlinkClusterChain(FF_IOMAN *pIoman, FF_T_UINT32 StartCluster, FF_ currentCluster = StartCluster; fatEntry = currentCluster; do { - fatEntry = FF_getFatEntry(pIoman, fatEntry); - FF_putFatEntry(pIoman, currentCluster, 0x00000000); + fatEntry = FF_getFatEntry(pIoman, fatEntry, &Error); + if(Error) { + return Error; + } + Error = FF_putFatEntry(pIoman, currentCluster, 0x00000000); + if(Error) { + return Error; + } + + if (lastFree > currentCluster) { + lastFree = currentCluster; + } currentCluster = fatEntry; iLen ++; }while(!FF_isEndOfChain(pIoman, fatEntry)); - FF_IncreaseFreeClusters(pIoman, iLen); + if (pIoman->pPartition->LastFreeCluster > lastFree) { + pIoman->pPartition->LastFreeCluster = lastFree; + } + Error = FF_IncreaseFreeClusters(pIoman, iLen); + if(Error) { + return Error; + } } else { // Truncation - This is quite hard, because we can only do it backwards. do { - fatEntry = FF_getFatEntry(pIoman, fatEntry); + fatEntry = FF_getFatEntry(pIoman, fatEntry, &Error); + if(Error) { + return Error; + } chainLength++; }while(!FF_isEndOfChain(pIoman, fatEntry)); } @@ -638,14 +710,19 @@ FF_T_SINT8 FF_UnlinkClusterChain(FF_IOMAN *pIoman, FF_T_UINT32 StartCluster, FF_ } #ifdef FF_FAT12_SUPPORT -FF_T_UINT32 FF_CountFreeClustersOLD(FF_IOMAN *pIoman) { +FF_T_UINT32 FF_CountFreeClustersOLD(FF_IOMAN *pIoman, FF_ERROR *pError) { FF_T_UINT32 i; FF_T_UINT32 TotalClusters = pIoman->pPartition->DataSectors / pIoman->pPartition->SectorsPerCluster; FF_T_UINT32 FatEntry; FF_T_UINT32 FreeClusters = 0; + *pError = FF_ERR_NONE; + for(i = 0; i < TotalClusters; i++) { - FatEntry = FF_getFatEntry(pIoman, i); + FatEntry = FF_getFatEntry(pIoman, i, pError); + if(*pError) { + return 0; + } if(!FatEntry) { FreeClusters++; } @@ -656,7 +733,7 @@ FF_T_UINT32 FF_CountFreeClustersOLD(FF_IOMAN *pIoman) { #endif -FF_T_UINT32 FF_CountFreeClusters(FF_IOMAN *pIoman) { +FF_T_UINT32 FF_CountFreeClusters(FF_IOMAN *pIoman, FF_ERROR *pError) { FF_BUFFER *pBuffer; FF_T_UINT32 i, x, nCluster = 0; FF_T_UINT32 FatOffset; @@ -666,9 +743,14 @@ FF_T_UINT32 FF_CountFreeClusters(FF_IOMAN *pIoman) { FF_T_UINT32 FatEntry = 1; FF_T_UINT32 FreeClusters = 0; + *pError = FF_ERR_NONE; + #ifdef FF_FAT12_SUPPORT if(pIoman->pPartition->Type == FF_T_FAT12) { // FAT12 tables are too small to optimise, and would make it very complicated! - return FF_CountFreeClustersOLD(pIoman); + FreeClusters = FF_CountFreeClustersOLD(pIoman, pError); + if(*pError) { + return 0; + } } #endif @@ -685,6 +767,10 @@ FF_T_UINT32 FF_CountFreeClusters(FF_IOMAN *pIoman) { for(i = 0; i < pIoman->pPartition->SectorsPerFAT; i++) { pBuffer = FF_GetBuffer(pIoman, pIoman->pPartition->FatBeginLBA + i, FF_MODE_READ); { + if(!pBuffer) { + *pError = FF_ERR_DEVICE_DRIVER_FAILED; + return 0; + } for(x = nCluster % EntriesPerSector; x < EntriesPerSector; x++) { if(pIoman->pPartition->Type == FF_T_FAT32) { FatOffset = x * 4; @@ -694,7 +780,7 @@ FF_T_UINT32 FF_CountFreeClusters(FF_IOMAN *pIoman) { } else { FatOffset = x * 2; FatSectorEntry = FatOffset % pIoman->pPartition->BlkSize; - FatEntry = (FF_T_UINT32) FF_getShort(pBuffer->pBuffer, (FF_T_UINT16)FatSectorEntry); + FatEntry = (FF_T_UINT32) FF_getShort(pBuffer->pBuffer, FatSectorEntry); } if(FatEntry == 0x00000000) { FreeClusters += 1; @@ -706,19 +792,27 @@ FF_T_UINT32 FF_CountFreeClusters(FF_IOMAN *pIoman) { FF_ReleaseBuffer(pIoman, pBuffer); } - return FreeClusters; + return FreeClusters <= pIoman->pPartition->NumClusters ? FreeClusters : pIoman->pPartition->NumClusters; } #ifdef FF_64_NUM_SUPPORT -FF_T_UINT64 FF_GetFreeSize(FF_IOMAN *pIoman) { +FF_T_UINT64 FF_GetFreeSize(FF_IOMAN *pIoman, FF_ERROR *pError) { FF_T_UINT32 FreeClusters; FF_T_UINT64 FreeSize; + FF_ERROR Error; if(pIoman) { FF_lockFAT(pIoman); { if(!pIoman->pPartition->FreeClusterCount) { - pIoman->pPartition->FreeClusterCount = FF_CountFreeClusters(pIoman); + pIoman->pPartition->FreeClusterCount = FF_CountFreeClusters(pIoman, &Error); + if(Error) { + if(pError) { + *pError = Error; + } + FF_unlockFAT(pIoman); + return 0; + } } FreeClusters = pIoman->pPartition->FreeClusterCount; } @@ -747,4 +841,4 @@ FF_T_UINT32 FF_GetFreeSize(FF_IOMAN *pIoman) { } return 0; } -#endif +#endif \ No newline at end of file diff --git a/lib/3rdparty/fullfat/ff_file.c b/lib/3rdparty/fullfat/ff_file.c index 7f982dc90d4..716467a7833 100644 --- a/lib/3rdparty/fullfat/ff_file.c +++ b/lib/3rdparty/fullfat/ff_file.c @@ -42,6 +42,11 @@ #include "ff_file.h" #include "ff_string.h" +#include "ff_config.h" + +#ifdef FF_UNICODE_SUPPORT +#include +#endif /** * @public @@ -143,13 +148,22 @@ FF_T_UINT8 FF_GetModeBits(FF_T_INT8 *Mode) { * @return NULL pointer on Error, in which case pError should be checked for more information. * @return pError can be: **/ +#ifdef FF_UNICODE_SUPPORT +FF_FILE *FF_Open(FF_IOMAN *pIoman, const FF_T_WCHAR *path, FF_T_UINT8 Mode, FF_ERROR *pError) { +#else FF_FILE *FF_Open(FF_IOMAN *pIoman, const FF_T_INT8 *path, FF_T_UINT8 Mode, FF_ERROR *pError) { +#endif FF_FILE *pFile; FF_FILE *pFileChain; FF_DIRENT Object; FF_T_UINT32 DirCluster, FileCluster; FF_T_UINT32 nBytesPerCluster; +#ifdef FF_UNICODE_SUPPORT + FF_T_WCHAR filename[FF_MAX_FILENAME]; +#else FF_T_INT8 filename[FF_MAX_FILENAME]; +#endif + FF_ERROR Error; FF_T_UINT16 i; @@ -163,7 +177,7 @@ FF_FILE *FF_Open(FF_IOMAN *pIoman, const FF_T_INT8 *path, FF_T_UINT8 Mode, FF_ER } return (FF_FILE *)NULL; } - pFile = FF_Malloc(sizeof(FF_FILE)); + pFile = FF_MALLOC(sizeof(FF_FILE)); if(!pFile) { if(pError) { *pError = FF_ERR_NOT_ENOUGH_MEMORY; @@ -174,7 +188,11 @@ FF_FILE *FF_Open(FF_IOMAN *pIoman, const FF_T_INT8 *path, FF_T_UINT8 Mode, FF_ER // Get the Mode Bits. pFile->Mode = Mode; +#ifdef FF_UNICODE_SUPPORT + i = (FF_T_UINT16) wcslen(path); +#else i = (FF_T_UINT16) strlen(path); +#endif while(i != 0) { if(path[i] == '\\' || path[i] == '/') { @@ -182,29 +200,45 @@ FF_FILE *FF_Open(FF_IOMAN *pIoman, const FF_T_INT8 *path, FF_T_UINT8 Mode, FF_ER } i--; } - +#ifdef FF_UNICODE_SUPPORT + wcsncpy(filename, (path + i + 1), FF_MAX_FILENAME); +#else strncpy(filename, (path + i + 1), FF_MAX_FILENAME); +#endif if(i == 0) { i = 1; } - DirCluster = FF_FindDir(pIoman, path, i); + DirCluster = FF_FindDir(pIoman, path, i, &Error); + if(Error) { + if(pError) { + *pError = Error; + } + FF_FREE(pFile); + return (FF_FILE *) NULL; + } if(DirCluster) { - //RetVal = //FF_FindEntry(pIoman, DirCluster, filename, &Object, FF_TRUE); - //if(RetVal >= 0) { - //FileCluster = Object.ObjectCluster;//FF_FindEntryInDir(pIoman, DirCluster, filename, 0x00, &Object); - //} else { - // FileCluster = 0; - //} - FileCluster = FF_FindEntryInDir(pIoman, DirCluster, filename, 0x00, &Object); + FileCluster = FF_FindEntryInDir(pIoman, DirCluster, filename, 0x00, &Object, &Error); + if(Error) { + if(pError) { + *pError = Error; + } + FF_FREE(pFile); + return (FF_FILE *) NULL; + } if(!FileCluster) { // If 0 was returned, it might be because the file has no allocated cluster +#ifdef FF_UNICODE_SUPPORT + if(wcslen(filename) == wcslen(Object.FileName)) { + if(Object.Filesize == 0 && FF_strmatch(filename, Object.FileName, (FF_T_UINT16) wcslen(filename)) == FF_TRUE) { +#else if(strlen(filename) == strlen(Object.FileName)) { if(Object.Filesize == 0 && FF_strmatch(filename, Object.FileName, (FF_T_UINT16) strlen(filename)) == FF_TRUE) { +#endif // The file really was found! FileCluster = 1; } @@ -213,7 +247,14 @@ FF_FILE *FF_Open(FF_IOMAN *pIoman, const FF_T_INT8 *path, FF_T_UINT8 Mode, FF_ER if(!FileCluster) { if((pFile->Mode & FF_MODE_CREATE)) { - FileCluster = FF_CreateFile(pIoman, DirCluster, filename, &Object); + FileCluster = FF_CreateFile(pIoman, DirCluster, filename, &Object, &Error); + if(Error) { + if(pError) { + *pError = Error; + } + FF_FREE(pFile); + return (FF_FILE *) NULL; + } Object.CurrentItem += 1; } } @@ -222,7 +263,7 @@ FF_FILE *FF_Open(FF_IOMAN *pIoman, const FF_T_INT8 *path, FF_T_UINT8 Mode, FF_ER if(Object.Attrib == FF_FAT_ATTR_DIR) { if(!(pFile->Mode & FF_MODE_DIR)) { // Not the object, File Not Found! - FF_Free(pFile); + FF_FREE(pFile); if(pError) { *pError = FF_ERR_FILE_OBJECT_IS_A_DIR; } @@ -233,7 +274,7 @@ FF_FILE *FF_Open(FF_IOMAN *pIoman, const FF_T_INT8 *path, FF_T_UINT8 Mode, FF_ER //---------- Ensure Read-Only files don't get opened for Writing. if((pFile->Mode & FF_MODE_WRITE) || (pFile->Mode & FF_MODE_APPEND)) { if((Object.Attrib & FF_FAT_ATTR_READONLY)) { - FF_Free(pFile); + FF_FREE(pFile); if(pError) { *pError = FF_ERR_FILE_IS_READ_ONLY; } @@ -276,7 +317,7 @@ FF_FILE *FF_Open(FF_IOMAN *pIoman, const FF_T_INT8 *path, FF_T_UINT8 Mode, FF_ER if(pFileChain->ObjectCluster == pFile->ObjectCluster) { // File is already open! DON'T ALLOW IT! FF_ReleaseSemaphore(pIoman->pSemaphore); - FF_Free(pFile); + FF_FREE(pFile); if(pError) { *pError = FF_ERR_FILE_ALREADY_OPEN; } @@ -294,7 +335,7 @@ FF_FILE *FF_Open(FF_IOMAN *pIoman, const FF_T_INT8 *path, FF_T_UINT8 Mode, FF_ER return pFile; }else { - FF_Free(pFile); + FF_FREE(pFile); if(pError) { *pError = FF_ERR_FILE_NOT_FOUND; } @@ -305,7 +346,7 @@ FF_FILE *FF_Open(FF_IOMAN *pIoman, const FF_T_INT8 *path, FF_T_UINT8 Mode, FF_ER *pError = FF_ERR_FILE_INVALID_PATH; } - FF_Free(pFile); + FF_FREE(pFile); return (FF_FILE *)NULL; } @@ -318,7 +359,11 @@ FF_FILE *FF_Open(FF_IOMAN *pIoman, const FF_T_INT8 *path, FF_T_UINT8 Mode, FF_ER * @param pIoman FF_IOMAN object returned from the FF_CreateIOMAN() function. * **/ +#ifdef FF_UNICODE_SUPPORT +FF_T_BOOL FF_isDirEmpty(FF_IOMAN *pIoman, const FF_T_WCHAR *Path) { +#else FF_T_BOOL FF_isDirEmpty(FF_IOMAN *pIoman, const FF_T_INT8 *Path) { +#endif FF_DIRENT MyDir; FF_ERROR RetVal = FF_ERR_NONE; @@ -340,11 +385,16 @@ FF_T_BOOL FF_isDirEmpty(FF_IOMAN *pIoman, const FF_T_INT8 *Path) { return FF_TRUE; } +#ifdef FF_UNICODE_SUPPORT +FF_ERROR FF_RmDir(FF_IOMAN *pIoman, const FF_T_WCHAR *path) { +#else FF_ERROR FF_RmDir(FF_IOMAN *pIoman, const FF_T_INT8 *path) { - FF_FILE *pFile; - FF_ERROR Error = FF_ERR_NONE; - FF_T_UINT8 EntryBuffer[32]; - FF_T_SINT8 RetVal = FF_ERR_NONE; +#endif + FF_FILE *pFile; + FF_ERROR Error = FF_ERR_NONE; + FF_T_UINT8 EntryBuffer[32]; + FF_FETCH_CONTEXT FetchContext; + FF_T_SINT8 RetVal = FF_ERR_NONE; #ifdef FF_PATH_CACHE FF_T_UINT32 i; #endif @@ -366,20 +416,57 @@ FF_ERROR FF_RmDir(FF_IOMAN *pIoman, const FF_T_INT8 *path) { if(FF_isDirEmpty(pIoman, path)) { FF_lockFAT(pIoman); { - FF_UnlinkClusterChain(pIoman, pFile->ObjectCluster, 0); // 0 to delete the entire chain! + Error = FF_UnlinkClusterChain(pIoman, pFile->ObjectCluster, 0); // 0 to delete the entire chain! } FF_unlockFAT(pIoman); + + if(Error) { + FF_unlockDIR(pIoman); + FF_Close(pFile); + return Error; + } + + // Initialise the dirent Fetch Context object for faster removal of dirents. + + Error = FF_InitEntryFetch(pIoman, pFile->DirCluster, &FetchContext); + if(Error) { + FF_unlockDIR(pIoman); + FF_Close(pFile); + return Error; + } // Edit the Directory Entry! (So it appears as deleted); - FF_RmLFNs(pIoman, pFile->DirCluster, pFile->DirEntry); - FF_FetchEntry(pIoman, pFile->DirCluster, pFile->DirEntry, EntryBuffer); + Error = FF_RmLFNs(pIoman, pFile->DirEntry, &FetchContext); + if(Error) { + FF_CleanupEntryFetch(pIoman, &FetchContext); + FF_unlockDIR(pIoman); + FF_Close(pFile); + return Error; + } + Error = FF_FetchEntryWithContext(pIoman, pFile->DirEntry, &FetchContext, EntryBuffer); + if(Error) { + FF_CleanupEntryFetch(pIoman, &FetchContext); + FF_unlockDIR(pIoman); + FF_Close(pFile); + return Error; + } EntryBuffer[0] = 0xE5; - FF_PushEntry(pIoman, pFile->DirCluster, pFile->DirEntry, EntryBuffer); + Error = FF_PushEntryWithContext(pIoman, pFile->DirEntry, &FetchContext, EntryBuffer); + if(Error) { + FF_CleanupEntryFetch(pIoman, &FetchContext); + FF_unlockDIR(pIoman); + FF_Close(pFile); + return Error; + } #ifdef FF_PATH_CACHE FF_PendSemaphore(pIoman->pSemaphore); // Thread safety on shared object! { for(i = 0; i < FF_PATH_CACHE_DEPTH; i++) { +#ifdef FF_UNICODE_SUPPORT + if(FF_strmatch(pIoman->pPartition->PathCache[i].Path, path, (FF_T_UINT16)wcslen(path))) { +#else if(FF_strmatch(pIoman->pPartition->PathCache[i].Path, path, (FF_T_UINT16)strlen(path))) { +#endif pIoman->pPartition->PathCache[i].Path[0] = '\0'; pIoman->pPartition->PathCache[i].DirCluster = 0; FF_ReleaseSemaphore(pIoman->pSemaphore); @@ -389,24 +476,46 @@ FF_ERROR FF_RmDir(FF_IOMAN *pIoman, const FF_T_INT8 *path) { FF_ReleaseSemaphore(pIoman->pSemaphore); #endif - FF_IncreaseFreeClusters(pIoman, pFile->iChainLength); + Error = FF_IncreaseFreeClusters(pIoman, pFile->iChainLength); + if(Error) { + FF_CleanupEntryFetch(pIoman, &FetchContext); + FF_unlockDIR(pIoman); + FF_Close(pFile); + return Error; + } - FF_FlushCache(pIoman); + FF_CleanupEntryFetch(pIoman, &FetchContext); + + Error = FF_FlushCache(pIoman); + if(Error) { + FF_unlockDIR(pIoman); + FF_Close(pFile); + return Error; + } } else { RetVal = FF_ERR_DIR_NOT_EMPTY; } } FF_unlockDIR(pIoman); - - FF_Close(pFile); // Free the file pointer resources + Error = FF_Close(pFile); // Free the file pointer resources + + if(Error) { + return Error; + } + // File is now lost! return RetVal; } +#ifdef FF_UNICODE_SUPPORT +FF_ERROR FF_RmFile(FF_IOMAN *pIoman, const FF_T_WCHAR *path) { +#else FF_ERROR FF_RmFile(FF_IOMAN *pIoman, const FF_T_INT8 *path) { +#endif FF_FILE *pFile; - FF_ERROR Error = 0; + FF_ERROR Error = FF_ERR_NONE; FF_T_UINT8 EntryBuffer[32]; + FF_FETCH_CONTEXT FetchContext; pFile = FF_Open(pIoman, path, FF_MODE_READ, &Error); @@ -416,26 +525,64 @@ FF_ERROR FF_RmFile(FF_IOMAN *pIoman, const FF_T_INT8 *path) { pFile->FileDeleted = FF_TRUE; - FF_lockFAT(pIoman); // Lock the FAT so its thread-safe. - { - FF_UnlinkClusterChain(pIoman, pFile->ObjectCluster, 0); // 0 to delete the entire chain! + if(pFile->ObjectCluster) { // Ensure there is actually a cluster chain to delete! + FF_lockFAT(pIoman); // Lock the FAT so its thread-safe. + { + Error = FF_UnlinkClusterChain(pIoman, pFile->ObjectCluster, 0); // 0 to delete the entire chain! + } + FF_unlockFAT(pIoman); + + if(Error) { + FF_Close(pFile); + return Error; + } } - FF_unlockFAT(pIoman); // Edit the Directory Entry! (So it appears as deleted); FF_lockDIR(pIoman); { - FF_RmLFNs(pIoman, pFile->DirCluster, pFile->DirEntry); - FF_FetchEntry(pIoman, pFile->DirCluster, pFile->DirEntry, EntryBuffer); + Error = FF_InitEntryFetch(pIoman, pFile->DirCluster, &FetchContext); + if(Error) { + FF_unlockDIR(pIoman); + FF_Close(pFile); + return Error; + } + Error = FF_RmLFNs(pIoman, pFile->DirEntry, &FetchContext); + if(Error) { + FF_CleanupEntryFetch(pIoman, &FetchContext); + FF_unlockDIR(pIoman); + FF_Close(pFile); + return Error; + } + Error = FF_FetchEntryWithContext(pIoman, pFile->DirEntry, &FetchContext, EntryBuffer); + if(Error) { + FF_CleanupEntryFetch(pIoman, &FetchContext); + FF_unlockDIR(pIoman); + FF_Close(pFile); + return Error; + } EntryBuffer[0] = 0xE5; - FF_PushEntry(pIoman, pFile->DirCluster, pFile->DirEntry, EntryBuffer); + + Error = FF_PushEntryWithContext(pIoman, pFile->DirEntry, &FetchContext, EntryBuffer); + if(Error) { + FF_CleanupEntryFetch(pIoman, &FetchContext); + FF_unlockDIR(pIoman); + FF_Close(pFile); + return Error; + } + + FF_CleanupEntryFetch(pIoman, &FetchContext); } FF_unlockDIR(pIoman); - FF_FlushCache(pIoman); + Error = FF_FlushCache(pIoman); + if(Error) { + FF_Close(pFile); + return Error; + } - FF_Close(pFile); // Free the file pointer resources - return 0; + Error = FF_Close(pFile); // Free the file pointer resources + return Error; } /** @@ -453,13 +600,18 @@ FF_ERROR FF_RmFile(FF_IOMAN *pIoman, const FF_T_INT8 *path) { * @return FF_ERR_FILE_SOURCE_NOT_FOUND if the source file was not found. * **/ +#ifdef FF_UNICODE_SUPPORT +FF_ERROR FF_Move(FF_IOMAN *pIoman, const FF_T_WCHAR *szSourceFile, const FF_T_WCHAR *szDestinationFile) { +#else FF_ERROR FF_Move(FF_IOMAN *pIoman, const FF_T_INT8 *szSourceFile, const FF_T_INT8 *szDestinationFile) { +#endif FF_ERROR Error; FF_FILE *pSrcFile, *pDestFile; FF_DIRENT MyFile; FF_T_UINT8 EntryBuffer[32]; FF_T_UINT16 i; FF_T_UINT32 DirCluster; + FF_FETCH_CONTEXT FetchContext; if(!pIoman) { return FF_ERR_NULL_POINTER; @@ -480,16 +632,34 @@ FF_ERROR FF_Move(FF_IOMAN *pIoman, const FF_T_INT8 *szSourceFile, const FF_T_INT pSrcFile = FF_Open(pIoman, szSourceFile, FF_MODE_DIR, &Error); } - if(pSrcFile) { + if(!pSrcFile) { + return Error; + } + if(pSrcFile) { // Create the new dirent. - FF_FetchEntry(pIoman, pSrcFile->DirCluster, pSrcFile->DirEntry, EntryBuffer); + Error = FF_InitEntryFetch(pIoman, pSrcFile->DirCluster, &FetchContext); + if(Error) { + FF_Close(pSrcFile); + return Error; + } + Error = FF_FetchEntryWithContext(pIoman, pSrcFile->DirEntry, &FetchContext, EntryBuffer); + if(Error) { + FF_Close(pSrcFile); + FF_CleanupEntryFetch(pIoman, &FetchContext); + return Error; + } + //FF_FetchEntry(pIoman, pSrcFile->DirCluster, pSrcFile->DirEntry, EntryBuffer); MyFile.Attrib = FF_getChar(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB)); MyFile.Filesize = pSrcFile->Filesize; MyFile.ObjectCluster = pSrcFile->ObjectCluster; MyFile.CurrentItem = 0; +#ifdef FF_UNICODE_SUPPORT + i = (FF_T_UINT16) wcslen(szDestinationFile); +#else i = (FF_T_UINT16) strlen(szDestinationFile); +#endif while(i != 0) { if(szDestinationFile[i] == '\\' || szDestinationFile[i] == '/') { @@ -498,30 +668,62 @@ FF_ERROR FF_Move(FF_IOMAN *pIoman, const FF_T_INT8 *szSourceFile, const FF_T_INT i--; } +#ifdef FF_UNICODE_SUPPORT + wcsncpy(MyFile.FileName, (szDestinationFile + i + 1), FF_MAX_FILENAME); +#else strncpy(MyFile.FileName, (szDestinationFile + i + 1), FF_MAX_FILENAME); +#endif if(i == 0) { i = 1; } - DirCluster = FF_FindDir(pIoman, szDestinationFile, i); + DirCluster = FF_FindDir(pIoman, szDestinationFile, i, &Error); + if(Error) { + FF_Close(pSrcFile); + FF_CleanupEntryFetch(pIoman, &FetchContext); + return Error; + } if(DirCluster) { // Destination Dir was found, we can now create the new entry. - if(FF_CreateDirent(pIoman, DirCluster, &MyFile)) { + Error = FF_CreateDirent(pIoman, DirCluster, &MyFile); + if(Error) { FF_Close(pSrcFile); - return FF_ERR_FILE_COULD_NOT_CREATE_DIRENT; // FAILED + FF_CleanupEntryFetch(pIoman, &FetchContext); + return Error; // FAILED } // Edit the Directory Entry! (So it appears as deleted); FF_lockDIR(pIoman); { - FF_RmLFNs(pIoman, pSrcFile->DirCluster, pSrcFile->DirEntry); - FF_FetchEntry(pIoman, pSrcFile->DirCluster, pSrcFile->DirEntry, EntryBuffer); + + Error = FF_RmLFNs(pIoman, pSrcFile->DirEntry, &FetchContext); + if(Error) { + FF_unlockDIR(pIoman); + FF_Close(pSrcFile); + FF_CleanupEntryFetch(pIoman, &FetchContext); + return Error; + } + Error = FF_FetchEntryWithContext(pIoman, pSrcFile->DirEntry, &FetchContext, EntryBuffer); + if(Error) { + FF_unlockDIR(pIoman); + FF_Close(pSrcFile); + FF_CleanupEntryFetch(pIoman, &FetchContext); + return Error; + } EntryBuffer[0] = 0xE5; - FF_PushEntry(pIoman, pSrcFile->DirCluster, pSrcFile->DirEntry, EntryBuffer); + //FF_PushEntry(pIoman, pSrcFile->DirCluster, pSrcFile->DirEntry, EntryBuffer); + Error = FF_PushEntryWithContext(pIoman, pSrcFile->DirEntry, &FetchContext, EntryBuffer); + if(Error) { + FF_unlockDIR(pIoman); + FF_Close(pSrcFile); + FF_CleanupEntryFetch(pIoman, &FetchContext); + return Error; + } + FF_CleanupEntryFetch(pIoman, &FetchContext); } FF_unlockDIR(pIoman); FF_Close(pSrcFile); @@ -560,14 +762,19 @@ FF_T_BOOL FF_isEOF(FF_FILE *pFile) { } } -static FF_T_UINT32 FF_GetSequentialClusters(FF_IOMAN *pIoman, FF_T_UINT32 StartCluster, FF_T_UINT32 Limit) { +static FF_T_UINT32 FF_GetSequentialClusters(FF_IOMAN *pIoman, FF_T_UINT32 StartCluster, FF_T_UINT32 Limit, FF_ERROR *pError) { FF_T_UINT32 CurrentCluster; FF_T_UINT32 NextCluster = StartCluster; FF_T_UINT32 i = 0; + *pError = FF_ERR_NONE; + do { CurrentCluster = NextCluster; - NextCluster = FF_getFatEntry(pIoman, CurrentCluster); + NextCluster = FF_getFatEntry(pIoman, CurrentCluster, pError); + if(*pError) { + return 0; + } if(NextCluster == (CurrentCluster + 1)) { i++; } else { @@ -584,41 +791,40 @@ static FF_T_UINT32 FF_GetSequentialClusters(FF_IOMAN *pIoman, FF_T_UINT32 StartC return i; } -static FF_T_SINT32 FF_ReadClusters(FF_FILE *pFile, FF_T_UINT32 Count, FF_T_UINT8 *buffer) { - FF_T_UINT32 Sectors; +static FF_ERROR FF_ReadClusters(FF_FILE *pFile, FF_T_UINT32 Count, FF_T_UINT8 *buffer) { + FF_T_UINT32 ulSectors; FF_T_UINT32 SequentialClusters = 0; FF_T_UINT32 nItemLBA; - FF_T_SINT32 RetVal; + FF_T_SINT32 slRetVal; + FF_ERROR Error; while(Count != 0) { if((Count - 1) > 0) { - SequentialClusters = FF_GetSequentialClusters(pFile->pIoman, pFile->AddrCurrentCluster, (Count - 1)); + SequentialClusters = FF_GetSequentialClusters(pFile->pIoman, pFile->AddrCurrentCluster, (Count - 1), &Error); + if(Error) { + return Error; + } } - Sectors = (SequentialClusters + 1) * pFile->pIoman->pPartition->SectorsPerCluster; + ulSectors = (SequentialClusters + 1) * pFile->pIoman->pPartition->SectorsPerCluster; nItemLBA = FF_Cluster2LBA(pFile->pIoman, pFile->AddrCurrentCluster); nItemLBA = FF_getRealLBA(pFile->pIoman, nItemLBA); - do { - if(pFile->pIoman->pBlkDevice->fnReadBlocks) { - RetVal = pFile->pIoman->pBlkDevice->fnReadBlocks(buffer, nItemLBA, Sectors, pFile->pIoman->pBlkDevice->pParam); - if(RetVal == FF_ERR_DRIVER_BUSY) { - FF_Yield(); - FF_Sleep(FF_DRIVER_BUSY_SLEEP); - } - } else { - RetVal = FF_ERR_DEVICE_DRIVER_FAILED; - } - - }while(RetVal == FF_ERR_DRIVER_BUSY); + slRetVal = FF_BlockRead(pFile->pIoman, nItemLBA, ulSectors, buffer); + if(slRetVal < 0) { + return slRetVal; + } Count -= (SequentialClusters + 1); - pFile->AddrCurrentCluster = FF_TraverseFAT(pFile->pIoman, pFile->AddrCurrentCluster, (SequentialClusters + 1)); + pFile->AddrCurrentCluster = FF_TraverseFAT(pFile->pIoman, pFile->AddrCurrentCluster, (SequentialClusters + 1), &Error); + if(Error) { + return Error; + } pFile->CurrentCluster += (SequentialClusters + 1); - buffer += Sectors * pFile->pIoman->BlkSize; + buffer += ulSectors * pFile->pIoman->BlkSize; SequentialClusters = 0; } - return 0; + return FF_ERR_NONE; } @@ -630,6 +836,7 @@ static FF_ERROR FF_ExtendFile(FF_FILE *pFile, FF_T_UINT32 Size) { FF_T_UINT32 CurrentCluster, NextCluster; FF_T_UINT32 i; FF_DIRENT OriginalEntry; + FF_ERROR Error; if((pFile->Mode & FF_MODE_WRITE) != FF_MODE_WRITE) { return FF_ERR_FILE_NOT_OPENED_IN_WRITE_MODE; @@ -637,13 +844,25 @@ static FF_ERROR FF_ExtendFile(FF_FILE *pFile, FF_T_UINT32 Size) { if(pFile->Filesize == 0 && pFile->ObjectCluster == 0) { // No Allocated clusters. // Create a Cluster chain! - pFile->AddrCurrentCluster = FF_CreateClusterChain(pFile->pIoman); - if(!FF_GetEntry(pIoman, pFile->DirEntry, pFile->DirCluster, &OriginalEntry)) { - OriginalEntry.ObjectCluster = pFile->AddrCurrentCluster; - FF_PutEntry(pIoman, pFile->DirEntry, pFile->DirCluster, &OriginalEntry); - } else { - return FF_ERR_FILE_EXTEND_FAILED; + pFile->AddrCurrentCluster = FF_CreateClusterChain(pFile->pIoman, &Error); + + if(Error) { + return Error; } + + Error = FF_GetEntry(pIoman, pFile->DirEntry, pFile->DirCluster, &OriginalEntry); + + if(!Error) { + OriginalEntry.ObjectCluster = pFile->AddrCurrentCluster; + Error = FF_PutEntry(pIoman, pFile->DirEntry, pFile->DirCluster, &OriginalEntry); + } else { + return Error; + } + + if(Error) { + return Error; + } + pFile->ObjectCluster = pFile->AddrCurrentCluster; pFile->iChainLength = 1; pFile->CurrentCluster = 0; @@ -655,7 +874,10 @@ static FF_ERROR FF_ExtendFile(FF_FILE *pFile, FF_T_UINT32 Size) { } if(pFile->iChainLength == 0) { // First extension requiring the chain length, - pFile->iChainLength = FF_GetChainLength(pIoman, pFile->ObjectCluster, &pFile->iEndOfChain); + pFile->iChainLength = FF_GetChainLength(pIoman, pFile->ObjectCluster, &pFile->iEndOfChain, &Error); + if(Error) { + return Error; + } } nClusterToExtend = (nTotalClustersNeeded - pFile->iChainLength); @@ -666,58 +888,88 @@ static FF_ERROR FF_ExtendFile(FF_FILE *pFile, FF_T_UINT32 Size) { FF_lockFAT(pIoman); { for(i = 0; i <= nClusterToExtend; i++) { - CurrentCluster = FF_FindEndOfChain(pIoman, NextCluster); - NextCluster = FF_FindFreeCluster(pIoman); + CurrentCluster = FF_FindEndOfChain(pIoman, NextCluster, &Error); + if(Error) { + FF_unlockFAT(pIoman); + FF_DecreaseFreeClusters(pIoman, i); + return Error; + } + NextCluster = FF_FindFreeCluster(pIoman, &Error); + if(Error) { + FF_unlockFAT(pIoman); + FF_DecreaseFreeClusters(pIoman, i); + return Error; + } if(!NextCluster) { FF_unlockFAT(pIoman); + FF_DecreaseFreeClusters(pIoman, i); return FF_ERR_FAT_NO_FREE_CLUSTERS; } - FF_putFatEntry(pIoman, CurrentCluster, NextCluster); - FF_putFatEntry(pIoman, NextCluster, 0xFFFFFFFF); + + Error = FF_putFatEntry(pIoman, CurrentCluster, NextCluster); + if(Error) { + FF_unlockFAT(pIoman); + FF_DecreaseFreeClusters(pIoman, i); + return Error; + } + Error = FF_putFatEntry(pIoman, NextCluster, 0xFFFFFFFF); + if(Error) { + FF_unlockFAT(pIoman); + FF_DecreaseFreeClusters(pIoman, i); + return Error; + } } - pFile->iEndOfChain = FF_FindEndOfChain(pIoman, NextCluster); + pFile->iEndOfChain = FF_FindEndOfChain(pIoman, NextCluster, &Error); + if(Error) { + FF_unlockFAT(pIoman); + FF_DecreaseFreeClusters(pIoman, i); + return Error; + } } FF_unlockFAT(pIoman); pFile->iChainLength += i; - FF_DecreaseFreeClusters(pIoman, i); // Keep Tab of Numbers for fast FreeSize() + Error = FF_DecreaseFreeClusters(pIoman, i); // Keep Tab of Numbers for fast FreeSize() + if(Error) { + return Error; + } } return FF_ERR_NONE; } -static FF_T_SINT32 FF_WriteClusters(FF_FILE *pFile, FF_T_UINT32 Count, FF_T_UINT8 *buffer) { - FF_T_UINT32 Sectors; +static FF_ERROR FF_WriteClusters(FF_FILE *pFile, FF_T_UINT32 Count, FF_T_UINT8 *buffer) { + FF_T_UINT32 ulSectors; FF_T_UINT32 SequentialClusters = 0; FF_T_UINT32 nItemLBA; - FF_T_SINT32 RetVal; + FF_T_SINT32 slRetVal; + FF_ERROR Error; while(Count != 0) { if((Count - 1) > 0) { - SequentialClusters = FF_GetSequentialClusters(pFile->pIoman, pFile->AddrCurrentCluster, (Count - 1)); + SequentialClusters = FF_GetSequentialClusters(pFile->pIoman, pFile->AddrCurrentCluster, (Count - 1), &Error); + if(Error) { + return Error; + } } - Sectors = (SequentialClusters + 1) * pFile->pIoman->pPartition->SectorsPerCluster; + ulSectors = (SequentialClusters + 1) * pFile->pIoman->pPartition->SectorsPerCluster; nItemLBA = FF_Cluster2LBA(pFile->pIoman, pFile->AddrCurrentCluster); nItemLBA = FF_getRealLBA(pFile->pIoman, nItemLBA); - do { - if(pFile->pIoman->pBlkDevice->fnWriteBlocks) { - RetVal = pFile->pIoman->pBlkDevice->fnWriteBlocks(buffer, nItemLBA, Sectors, pFile->pIoman->pBlkDevice->pParam); - if(RetVal == FF_ERR_DRIVER_BUSY) { - FF_Yield(); - FF_Sleep(FF_DRIVER_BUSY_SLEEP); - } - } else { - RetVal = FF_ERR_DEVICE_DRIVER_FAILED; - } - - }while(RetVal == FF_ERR_DRIVER_BUSY); + slRetVal = FF_BlockWrite(pFile->pIoman, nItemLBA, ulSectors, buffer); + + if(slRetVal < 0) { + return slRetVal; + } Count -= (SequentialClusters + 1); - pFile->AddrCurrentCluster = FF_TraverseFAT(pFile->pIoman, pFile->AddrCurrentCluster, (SequentialClusters + 1)); + pFile->AddrCurrentCluster = FF_TraverseFAT(pFile->pIoman, pFile->AddrCurrentCluster, (SequentialClusters + 1), &Error); + if(Error) { + return Error; + } pFile->CurrentCluster += (SequentialClusters + 1); - buffer += Sectors * pFile->pIoman->BlkSize; + buffer += ulSectors * pFile->pIoman->BlkSize; SequentialClusters = 0; } @@ -749,6 +1001,7 @@ FF_T_SINT32 FF_Read(FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, FF_T_UINT32 nRelClusterPos; FF_T_UINT32 nBytesPerCluster; FF_T_UINT32 nClusterDiff; + FF_ERROR Error; if(!pFile) { return FF_ERR_NULL_POINTER; @@ -771,7 +1024,10 @@ FF_T_SINT32 FF_Read(FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster; if(nClusterDiff) { if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) { - pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff); + pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff, &Error); + if(Error) { + return Error; + } pFile->CurrentCluster += nClusterDiff; } } @@ -784,6 +1040,9 @@ FF_T_SINT32 FF_Read(FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, if((nRelBlockPos + nBytes) < pIoman->BlkSize) { // Bytes to read are within a block and less than a block size. pBuffer = FF_GetBuffer(pIoman, nItemLBA, FF_MODE_READ); { + if(!pBuffer) { + return FF_ERR_DEVICE_DRIVER_FAILED; + } memcpy(buffer, (pBuffer->pBuffer + nRelBlockPos), nBytes); } FF_ReleaseBuffer(pIoman, pBuffer); @@ -799,6 +1058,9 @@ FF_T_SINT32 FF_Read(FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, nBytesToRead = pIoman->BlkSize - nRelBlockPos; pBuffer = FF_GetBuffer(pIoman, nItemLBA, FF_MODE_READ); { + if(!pBuffer) { + return FF_ERR_DEVICE_DRIVER_FAILED; + } // Here we copy to the sector boudary. memcpy(buffer, (pBuffer->pBuffer + nRelBlockPos), nBytesToRead); } @@ -820,7 +1082,10 @@ FF_T_SINT32 FF_Read(FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster; if(nClusterDiff) { if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) { - pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff); + pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff, &Error); + if(Error) { + return Error; + } pFile->CurrentCluster += nClusterDiff; } } @@ -830,15 +1095,7 @@ FF_T_SINT32 FF_Read(FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, sSectors = (FF_T_UINT16) (pIoman->pPartition->SectorsPerCluster - (nRelClusterPos / pIoman->BlkSize)); - do { - if(pIoman->pBlkDevice->fnReadBlocks) { - RetVal = pFile->pIoman->pBlkDevice->fnReadBlocks(buffer, nItemLBA, sSectors, pIoman->pBlkDevice->pParam); - } - if(RetVal == FF_ERR_DRIVER_BUSY) { - FF_Yield(); - FF_Sleep(FF_DRIVER_BUSY_SLEEP); - } - }while(RetVal == FF_ERR_DRIVER_BUSY); + RetVal = FF_BlockRead(pIoman, nItemLBA, (FF_T_UINT32) sSectors, buffer); nBytesToRead = sSectors * pIoman->BlkSize; nBytes -= nBytesToRead; @@ -854,13 +1111,19 @@ FF_T_SINT32 FF_Read(FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster; if(nClusterDiff) { if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) { - pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff); + pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff, &Error); + if(Error) { + return Error; + } pFile->CurrentCluster += nClusterDiff; } } //----- End of Contributor fix. - FF_ReadClusters(pFile, (nBytes / nBytesPerCluster), buffer); + RetVal = FF_ReadClusters(pFile, (nBytes / nBytesPerCluster), buffer); + if(RetVal < 0) { + return RetVal; + } nBytesToRead = (nBytesPerCluster * (nBytes / nBytesPerCluster)); pFile->FilePointer += nBytesToRead; @@ -877,23 +1140,22 @@ FF_T_SINT32 FF_Read(FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster; if(nClusterDiff) { if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) { - pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff); + pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff, &Error); + if(Error) { + return Error; + } pFile->CurrentCluster += nClusterDiff; } } nItemLBA = FF_Cluster2LBA(pIoman, pFile->AddrCurrentCluster); nItemLBA = FF_getRealLBA(pIoman, nItemLBA + FF_getMajorBlockNumber(pIoman, pFile->FilePointer, 1)) + FF_getMinorBlockNumber(pIoman, pFile->FilePointer, 1); - - do { - if(pIoman->pBlkDevice->fnReadBlocks) { - RetVal = pFile->pIoman->pBlkDevice->fnReadBlocks(buffer, nItemLBA, sSectors, pIoman->pBlkDevice->pParam); - } - if(RetVal == FF_ERR_DRIVER_BUSY) { - FF_Yield(); - FF_Sleep(FF_DRIVER_BUSY_SLEEP); - } - }while(RetVal == FF_ERR_DRIVER_BUSY); + + RetVal = FF_BlockRead(pIoman, nItemLBA, (FF_T_UINT32) sSectors, buffer); + + if(RetVal < 0) { + return RetVal; + } nBytesToRead = sSectors * pIoman->BlkSize; pFile->FilePointer += nBytesToRead; @@ -908,7 +1170,10 @@ FF_T_SINT32 FF_Read(FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster; if(nClusterDiff) { if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) { - pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff); + pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff, &Error); + if(Error) { + return Error; + } pFile->CurrentCluster += nClusterDiff; } } @@ -917,6 +1182,9 @@ FF_T_SINT32 FF_Read(FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, nItemLBA = FF_getRealLBA(pIoman, nItemLBA + FF_getMajorBlockNumber(pIoman, pFile->FilePointer, 1)) + FF_getMinorBlockNumber(pIoman, pFile->FilePointer, 1); pBuffer = FF_GetBuffer(pIoman, nItemLBA, FF_MODE_READ); { + if(!pBuffer) { + return FF_ERR_DEVICE_DRIVER_FAILED; + } memcpy(buffer, pBuffer->pBuffer, nBytes); } FF_ReleaseBuffer(pIoman, pBuffer); @@ -954,6 +1222,7 @@ FF_T_SINT32 FF_GetC(FF_FILE *pFile) { FF_T_UINT32 relMinorBlockPos; FF_T_UINT32 clusterNum; FF_T_UINT32 nClusterDiff; + FF_ERROR Error; if(!pFile) { @@ -974,7 +1243,10 @@ FF_T_SINT32 FF_GetC(FF_FILE *pFile) { nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster; if(nClusterDiff) { if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) { - pFile->AddrCurrentCluster = FF_TraverseFAT(pFile->pIoman, pFile->AddrCurrentCluster, nClusterDiff); + pFile->AddrCurrentCluster = FF_TraverseFAT(pFile->pIoman, pFile->AddrCurrentCluster, nClusterDiff, &Error); + if(Error) { + return Error; + } pFile->CurrentCluster += nClusterDiff; } } @@ -986,7 +1258,7 @@ FF_T_SINT32 FF_GetC(FF_FILE *pFile) { pBuffer = FF_GetBuffer(pFile->pIoman, fileLBA, FF_MODE_READ); { if(!pBuffer) { - return -3; + return FF_ERR_DEVICE_DRIVER_FAILED; } retChar = pBuffer->pBuffer[relMinorBlockPos]; } @@ -997,6 +1269,45 @@ FF_T_SINT32 FF_GetC(FF_FILE *pFile) { return (FF_T_INT32) retChar; } + +/** + * @public + * @brief Gets a Line from a Text File, but no more than ulLimit charachters. The line will be NULL terminated. + * + * The behaviour of this function is undefined when called on a binary file. + * It should just read in ulLimit bytes of binary, and ZERO terminate the line. + * + * This function works for both UNIX line feeds, and Windows CRLF type files. + * + * @param pFile The FF_FILE object pointer. + * @param szLine The charachter buffer where the line should be stored. + * @param ulLimit This should be the max number of charachters that szLine can hold. + * + * @return The number of charachters read from the line, on success. + * @return 0 when no more lines are available, or when ulLimit is 0. + * @return FF_ERR_NULL_POINTER if pFile or szLine are NULL; + * + **/ +FF_T_SINT32 FF_GetLine(FF_FILE *pFile, FF_T_INT8 *szLine, FF_T_UINT32 ulLimit) { + FF_T_SINT32 c; + FF_T_UINT32 i; + + if(!pFile || !szLine) { + return FF_ERR_NULL_POINTER; + } + + for(i = 0; i < (ulLimit - 1) && (c=FF_GetC(pFile)) >= 0 && c != '\n'; ++i) { + if(c == '\r') { + i--; + } else { + szLine[i] = (FF_T_INT8) c; + } + } + + szLine[i] = '\0'; + return i; +} + FF_T_UINT32 FF_Tell(FF_FILE *pFile) { return pFile->FilePointer; } @@ -1021,7 +1332,7 @@ FF_T_SINT32 FF_Write(FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, FF_BUFFER *pBuffer; FF_T_UINT32 nRelBlockPos; FF_T_UINT32 nItemLBA; - FF_T_SINT32 RetVal = 0; + FF_T_SINT32 slRetVal = 0; FF_T_UINT16 sSectors; FF_T_UINT32 nRelClusterPos; FF_T_UINT32 nBytesPerCluster, nClusterDiff, nClusters; @@ -1059,7 +1370,10 @@ FF_T_SINT32 FF_Write(FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster; if(nClusterDiff) { if(pFile->CurrentCluster != FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) { - pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff); + pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff, &Error); + if(Error) { + return Error; + } pFile->CurrentCluster += nClusterDiff; } } @@ -1070,6 +1384,9 @@ FF_T_SINT32 FF_Write(FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, if((nRelBlockPos + nBytes) < pIoman->BlkSize) { // Bytes to read are within a block and less than a block size. pBuffer = FF_GetBuffer(pIoman, nItemLBA, FF_MODE_WRITE); { + if(!pBuffer) { + return FF_ERR_DEVICE_DRIVER_FAILED; + } memcpy((pBuffer->pBuffer + nRelBlockPos), buffer, nBytes); } FF_ReleaseBuffer(pIoman, pBuffer); @@ -1085,6 +1402,9 @@ FF_T_SINT32 FF_Write(FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, nBytesToWrite = pIoman->BlkSize - nRelBlockPos; pBuffer = FF_GetBuffer(pIoman, nItemLBA, FF_MODE_WRITE); { + if(!pBuffer) { + return FF_ERR_DEVICE_DRIVER_FAILED; + } // Here we copy to the sector boudary. memcpy((pBuffer->pBuffer + nRelBlockPos), buffer, nBytesToWrite); } @@ -1104,7 +1424,10 @@ FF_T_SINT32 FF_Write(FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster; if(nClusterDiff) { if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) { - pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff); + pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff, &Error); + if(Error) { + return Error; + } pFile->CurrentCluster += nClusterDiff; } } @@ -1113,16 +1436,11 @@ FF_T_SINT32 FF_Write(FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, nItemLBA = FF_getRealLBA(pIoman, nItemLBA + FF_getMajorBlockNumber(pIoman, pFile->FilePointer, 1)) + FF_getMinorBlockNumber(pIoman, pFile->FilePointer, 1); sSectors = (FF_T_UINT16) (pIoman->pPartition->SectorsPerCluster - (nRelClusterPos / pIoman->BlkSize)); - - do { - if(pIoman->pBlkDevice->fnWriteBlocks) { - RetVal = pFile->pIoman->pBlkDevice->fnWriteBlocks(buffer, nItemLBA, sSectors, pIoman->pBlkDevice->pParam); - } - if(RetVal == FF_ERR_DRIVER_BUSY) { - FF_Yield(); - FF_Sleep(FF_DRIVER_BUSY_SLEEP); - } - }while(RetVal == FF_ERR_DRIVER_BUSY); + + slRetVal = FF_BlockWrite(pFile->pIoman, nItemLBA, sSectors, buffer); + if(slRetVal < 0) { + return slRetVal; + } nBytesToWrite = sSectors * pIoman->BlkSize; nBytes -= nBytesToWrite; @@ -1138,7 +1456,10 @@ FF_T_SINT32 FF_Write(FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster; if(nClusterDiff) { if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) { - pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff); + pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff, &Error); + if(Error) { + return Error; + } pFile->CurrentCluster += nClusterDiff; } } @@ -1146,7 +1467,10 @@ FF_T_SINT32 FF_Write(FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, nClusters = (nBytes / nBytesPerCluster); - FF_WriteClusters(pFile, nClusters, buffer); + slRetVal = FF_WriteClusters(pFile, nClusters, buffer); + if(slRetVal < 0) { + return slRetVal; + } nBytesToWrite = (nBytesPerCluster * nClusters); @@ -1164,7 +1488,10 @@ FF_T_SINT32 FF_Write(FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster; if(nClusterDiff) { if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) { - pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff); + pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff, &Error); + if(Error) { + return Error; + } pFile->CurrentCluster += nClusterDiff; } } @@ -1172,22 +1499,16 @@ FF_T_SINT32 FF_Write(FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, nItemLBA = FF_Cluster2LBA(pIoman, pFile->AddrCurrentCluster); nItemLBA = FF_getRealLBA(pIoman, nItemLBA + FF_getMajorBlockNumber(pIoman, pFile->FilePointer, 1)) + FF_getMinorBlockNumber(pIoman, pFile->FilePointer, 1); - do { - if(pIoman->pBlkDevice->fnWriteBlocks) { - RetVal = pFile->pIoman->pBlkDevice->fnWriteBlocks(buffer, nItemLBA, sSectors, pIoman->pBlkDevice->pParam); - } - if(RetVal == FF_ERR_DRIVER_BUSY) { - FF_Yield(); - FF_Sleep(FF_DRIVER_BUSY_SLEEP); - } - }while(RetVal == FF_ERR_DRIVER_BUSY); + slRetVal = FF_BlockWrite(pFile->pIoman, nItemLBA, sSectors, buffer); + if(slRetVal < 0) { + return slRetVal; + } nBytesToWrite = sSectors * pIoman->BlkSize; pFile->FilePointer += nBytesToWrite; nBytes -= nBytesToWrite; buffer += nBytesToWrite; nBytesWritten += nBytesToWrite; - } //---------- Write (memcpy) Remaining Bytes @@ -1196,7 +1517,10 @@ FF_T_SINT32 FF_Write(FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster; if(nClusterDiff) { if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) { - pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff); + pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff, &Error); + if(Error) { + return Error; + } pFile->CurrentCluster += nClusterDiff; } } @@ -1205,6 +1529,9 @@ FF_T_SINT32 FF_Write(FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, nItemLBA = FF_getRealLBA(pIoman, nItemLBA + FF_getMajorBlockNumber(pIoman, pFile->FilePointer, 1)) + FF_getMinorBlockNumber(pIoman, pFile->FilePointer, 1); pBuffer = FF_GetBuffer(pIoman, nItemLBA, FF_MODE_WRITE); { + if(!pBuffer) { + return FF_ERR_DEVICE_DRIVER_FAILED; + } memcpy(pBuffer->pBuffer, buffer, nBytes); } FF_ReleaseBuffer(pIoman, pBuffer); @@ -1241,6 +1568,7 @@ FF_T_SINT32 FF_PutC(FF_FILE *pFile, FF_T_UINT8 pa_cValue) { FF_T_UINT32 iItemLBA; FF_T_UINT32 iRelPos; FF_T_UINT32 nClusterDiff; + FF_ERROR Error; if(!pFile) { // Ensure we don't have a Null file pointer on a Public interface. return FF_ERR_NULL_POINTER; @@ -1260,18 +1588,24 @@ FF_T_SINT32 FF_PutC(FF_FILE *pFile, FF_T_UINT8 pa_cValue) { iRelPos = FF_getMinorBlockEntry(pFile->pIoman, pFile->FilePointer, 1); // Handle File Space Allocation. - FF_ExtendFile(pFile, pFile->FilePointer + 1); + Error = FF_ExtendFile(pFile, pFile->FilePointer + 1); + if(Error) { + return Error; + } nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster; if(nClusterDiff) { if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) { - pFile->AddrCurrentCluster = FF_TraverseFAT(pFile->pIoman, pFile->AddrCurrentCluster, nClusterDiff); + pFile->AddrCurrentCluster = FF_TraverseFAT(pFile->pIoman, pFile->AddrCurrentCluster, nClusterDiff, &Error); + if(Error) { + return Error; + } pFile->CurrentCluster += nClusterDiff; } } iItemLBA = FF_Cluster2LBA(pFile->pIoman, pFile->AddrCurrentCluster) + FF_getMajorBlockNumber(pFile->pIoman, pFile->FilePointer, (FF_T_UINT16) 1); - iItemLBA = FF_getRealLBA (pFile->pIoman, iItemLBA) + FF_getMinorBlockNumber(pFile->pIoman, pFile->FilePointer, (FF_T_UINT16) 1); + iItemLBA = FF_getRealLBA (pFile->pIoman, iItemLBA) + FF_getMinorBlockNumber(pFile->pIoman, pFile->FilePointer, (FF_T_UINT16) 1); pBuffer = FF_GetBuffer(pFile->pIoman, iItemLBA, FF_MODE_WRITE); { @@ -1301,22 +1635,32 @@ FF_T_SINT32 FF_PutC(FF_FILE *pFile, FF_T_UINT8 pa_cValue) { * * @return 0 on Sucess, * @return -2 if offset results in an invalid position in the file. - * @return -1 if a FF_FILE pointer was not recieved. + * @return FF_ERR_NULL_POINTER if a FF_FILE pointer was not recieved. * @return -3 if an invalid origin was provided. * **/ FF_ERROR FF_Seek(FF_FILE *pFile, FF_T_SINT32 Offset, FF_T_INT8 Origin) { + FF_ERROR Error; + if(!pFile) { return FF_ERR_NULL_POINTER; } + Error = FF_FlushCache(pFile->pIoman); + if(Error) { + return Error; + } + switch(Origin) { case FF_SEEK_SET: if((FF_T_UINT32) Offset <= pFile->Filesize && Offset >= 0) { pFile->FilePointer = Offset; pFile->CurrentCluster = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1); - pFile->AddrCurrentCluster = FF_TraverseFAT(pFile->pIoman, pFile->ObjectCluster, pFile->CurrentCluster); + pFile->AddrCurrentCluster = FF_TraverseFAT(pFile->pIoman, pFile->ObjectCluster, pFile->CurrentCluster, &Error); + if(Error) { + return Error; + } } else { return -2; } @@ -1326,7 +1670,10 @@ FF_ERROR FF_Seek(FF_FILE *pFile, FF_T_SINT32 Offset, FF_T_INT8 Origin) { if((Offset + pFile->FilePointer) <= pFile->Filesize && (Offset + (FF_T_SINT32) pFile->FilePointer) >= 0) { pFile->FilePointer = Offset + pFile->FilePointer; pFile->CurrentCluster = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1); - pFile->AddrCurrentCluster = FF_TraverseFAT(pFile->pIoman, pFile->ObjectCluster, pFile->CurrentCluster); + pFile->AddrCurrentCluster = FF_TraverseFAT(pFile->pIoman, pFile->ObjectCluster, pFile->CurrentCluster, &Error); + if(Error) { + return Error; + } } else { return -2; } @@ -1336,7 +1683,10 @@ FF_ERROR FF_Seek(FF_FILE *pFile, FF_T_SINT32 Offset, FF_T_INT8 Origin) { if((Offset + (FF_T_SINT32) pFile->Filesize) >= 0 && (Offset + pFile->Filesize) <= pFile->Filesize) { pFile->FilePointer = Offset + pFile->Filesize; pFile->CurrentCluster = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1); - pFile->AddrCurrentCluster = FF_TraverseFAT(pFile->pIoman, pFile->ObjectCluster, pFile->CurrentCluster); + pFile->AddrCurrentCluster = FF_TraverseFAT(pFile->pIoman, pFile->ObjectCluster, pFile->CurrentCluster, &Error); + if(Error) { + return Error; + } } else { return -2; } @@ -1381,14 +1731,15 @@ FF_ERROR FF_Close(FF_FILE *pFile) { if(!pFile->FileDeleted) { if(pFile->Filesize != OriginalEntry.Filesize) { OriginalEntry.Filesize = pFile->Filesize; - FF_PutEntry(pFile->pIoman, pFile->DirEntry, pFile->DirCluster, &OriginalEntry); + Error = FF_PutEntry(pFile->pIoman, pFile->DirEntry, pFile->DirCluster, &OriginalEntry); + if(Error) { + return Error; + } } } - //if(pFile->Mode == FF_MODE_WRITE) { - FF_FlushCache(pFile->pIoman); // Ensure all modfied blocks are flushed to disk! - //} - + Error = FF_FlushCache(pFile->pIoman); // Ensure all modfied blocks are flushed to disk! + // Handle Linked list! FF_PendSemaphore(pFile->pIoman->pSemaphore); { // Semaphore is required, or linked list could become corrupted. @@ -1405,7 +1756,12 @@ FF_ERROR FF_Close(FF_FILE *pFile) { FF_ReleaseSemaphore(pFile->pIoman->pSemaphore); // If file written, flush to disk - FF_Free(pFile); + FF_FREE(pFile); + + if(Error) { + return Error; + } + // Simply free the pointer! return FF_ERR_NONE; } diff --git a/lib/3rdparty/fullfat/ff_format.c b/lib/3rdparty/fullfat/ff_format.c new file mode 100644 index 00000000000..8799f9a204e --- /dev/null +++ b/lib/3rdparty/fullfat/ff_format.c @@ -0,0 +1,132 @@ +/***************************************************************************** + * FullFAT - High Performance, Thread-Safe Embedded FAT File-System * + * Copyright (C) 2009 James Walmsley (james@worm.me.uk) * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + * * + * IMPORTANT NOTICE: * + * ================= * + * Alternative Licensing is available directly from the Copyright holder, * + * (James Walmsley). For more information consult LICENSING.TXT to obtain * + * a Commercial license. * + * * + * See RESTRICTIONS.TXT for extra restrictions on the use of FullFAT. * + * * + * Removing the above notice is illegal and will invalidate this license. * + ***************************************************************************** + * See http://worm.me.uk/fullfat for more information. * + * Or http://fullfat.googlecode.com/ for latest releases and the wiki. * + *****************************************************************************/ + +/** + * @file ff_format.c + * @author James Walmsley + * @ingroup FORMAT + * + * @defgroup FORMAT Independent FAT Formatter + * @brief Provides an interface to format a partition with FAT. + * + * + * + **/ + + +#include "ff_format.h" +#include "ff_types.h" +#include "ff_ioman.h" +#include "ff_fatdef.h" + +static FF_T_SINT8 FF_PartitionCount (FF_T_UINT8 *pBuffer) +{ + FF_T_SINT8 count = 0; + FF_T_SINT8 part; + // Check PBR or MBR signature + if (FF_getChar(pBuffer, FF_FAT_MBR_SIGNATURE) != 0x55 && + FF_getChar(pBuffer, FF_FAT_MBR_SIGNATURE) != 0xAA ) { + // No MBR, but is it a PBR ? + if (FF_getChar(pBuffer, 0) == 0xEB && // PBR Byte 0 + FF_getChar(pBuffer, 2) == 0x90 && // PBR Byte 2 + (FF_getChar(pBuffer, 21) & 0xF0) == 0xF0) {// PBR Byte 21 : Media byte + return 1; // No MBR but PBR exist then only one partition + } + return 0; // No MBR and no PBR then no partition found + } + for (part = 0; part < 4; part++) { + FF_T_UINT8 active = FF_getChar(pBuffer, FF_FAT_PTBL + FF_FAT_PTBL_ACTIVE + (16 * part)); + FF_T_UINT8 part_id = FF_getChar(pBuffer, FF_FAT_PTBL + FF_FAT_PTBL_ID + (16 * part)); + // The first sector must be a MBR, then check the partition entry in the MBR + if (active != 0x80 && (active != 0 || part_id == 0)) { + break; + } + count++; + } + return count; +} + +FF_ERROR FF_FormatPartition(FF_IOMAN *pIoman, FF_T_UINT32 ulPartitionNumber, FF_T_UINT32 ulClusterSize) { + + FF_BUFFER *pBuffer; + FF_T_UINT8 ucPartitionType; + FF_T_SINT8 scPartitionCount; + + FF_T_UINT32 /*ulPartitionBeginLBA, ulPartitionLength,*/ ulPnum; + + FF_ERROR Error = FF_ERR_NONE; + + ulClusterSize = 0; + + // Get Partition Metrics, and pass on to FF_Format() function + + pBuffer = FF_GetBuffer(pIoman, 0, FF_MODE_READ); + { + if(!pBuffer) { + return FF_ERR_DEVICE_DRIVER_FAILED; + } + + scPartitionCount = FF_PartitionCount(pBuffer->pBuffer); + + ucPartitionType = FF_getChar(pBuffer->pBuffer, FF_FAT_PTBL + FF_FAT_PTBL_ID); + + if(ucPartitionType == 0xEE) { + // Handle Extended Partitions + ulPnum = 0; + } else { + if(ulPartitionNumber > (FF_T_UINT32) scPartitionCount) { + FF_ReleaseBuffer(pIoman, pBuffer); + return FF_ERR_IOMAN_INVALID_PARTITION_NUM; + } + ulPnum = ulPartitionNumber; + } + + } + FF_ReleaseBuffer(pIoman, pBuffer); + + + + return Error; + +} + +FF_ERROR FF_Format(FF_IOMAN *pIoman, FF_T_UINT32 ulStartLBA, FF_T_UINT32 ulEndLBA, FF_T_UINT32 ulClusterSize) { + FF_T_UINT32 ulTotalSectors; + FF_T_UINT32 ulTotalClusters; + + ulTotalSectors = ulEndLBA - ulStartLBA; + ulTotalClusters = ulTotalSectors / (ulClusterSize / pIoman->BlkSize); + + + return -1; + + +} \ No newline at end of file diff --git a/lib/3rdparty/fullfat/ff_hash.c b/lib/3rdparty/fullfat/ff_hash.c index 5bcaf4c66d2..6357987b313 100644 --- a/lib/3rdparty/fullfat/ff_hash.c +++ b/lib/3rdparty/fullfat/ff_hash.c @@ -43,9 +43,9 @@ #include #include -#ifdef FF_HASH_TABLE_SUPPORT +#ifdef FF_HASH_CACHE struct _FF_HASH_TABLE { - FF_T_UINT8 bitTable[FF_HASH_TABLE_SIZE]; + FF_T_UINT8 bitTable[FF_HASH_TABLE_SIZE]; }; /** @@ -53,7 +53,7 @@ struct _FF_HASH_TABLE { * **/ FF_HASH_TABLE FF_CreateHashTable() { - FF_HASH_TABLE pHash = (FF_HASH_TABLE) FF_Malloc(sizeof(struct _FF_HASH_TABLE)); + FF_HASH_TABLE pHash = (FF_HASH_TABLE) FF_MALLOC(sizeof(struct _FF_HASH_TABLE)); if(pHash) { FF_ClearHashTable(pHash); @@ -110,7 +110,7 @@ FF_T_BOOL FF_isHashSet(FF_HASH_TABLE pHash, FF_T_UINT32 nHash) { FF_ERROR FF_DestroyHashTable(FF_HASH_TABLE pHash) { if(pHash) { - free(pHash); + FF_FREE(pHash); return FF_ERR_NONE; } return FF_ERR_NULL_POINTER; diff --git a/lib/3rdparty/fullfat/ff_ioman.c b/lib/3rdparty/fullfat/ff_ioman.c index c30126d3f28..8e8fc32d418 100644 --- a/lib/3rdparty/fullfat/ff_ioman.c +++ b/lib/3rdparty/fullfat/ff_ioman.c @@ -42,11 +42,14 @@ * Destroying a FullFAT IO object. **/ -#include "ff_ioman.h" // Includes ff_types.h, ff_safety.h, -#include "fat.h" +#include -extern FF_T_UINT32 FF_FindFreeCluster (FF_IOMAN *pIoman); -extern FF_T_UINT32 FF_CountFreeClusters (FF_IOMAN *pIoman); +#include "ff_ioman.h" // Includes ff_types.h, ff_safety.h, +#include "ff_fatdef.h" +#include "ff_crc.h" + +//extern FF_T_UINT32 FF_FindFreeCluster (FF_IOMAN *pIoman); +extern FF_T_UINT32 FF_CountFreeClusters (FF_IOMAN *pIoman, FF_ERROR *pError); static void FF_IOMAN_InitBufferDescriptors(FF_IOMAN *pIoman); @@ -55,7 +58,7 @@ static void FF_IOMAN_InitBufferDescriptors(FF_IOMAN *pIoman); * @brief Creates an FF_IOMAN object, to initialise FullFAT * * @param pCacheMem Pointer to a buffer for the cache. (NULL if ok to Malloc). - * @param Size The size of the provided buffer, or size of the cache to be created. + * @param Size The size of the provided buffer, or size of the cache to be created. (Must be atleast 2 * BlkSize). Always a multiple of BlkSize. * @param BlkSize The block size of devices to be attached. If in doubt use 512. * @param pError Pointer to a signed byte for error checking. Can be NULL if not required. * @param pError To be checked when a NULL pointer is returned. @@ -75,85 +78,99 @@ FF_IOMAN *FF_CreateIOMAN(FF_T_UINT8 *pCacheMem, FF_T_UINT32 Size, FF_T_UINT16 Bl *pError = FF_ERR_NONE; } - if((BlkSize % 512) != 0 || Size == 0) { + if((BlkSize % 512) != 0 || BlkSize == 0) { if(pError) { - *pError = FF_ERR_IOMAN_BAD_BLKSIZE; + *pError = FF_ERR_IOMAN_BAD_BLKSIZE | FF_CREATEIOMAN; } return NULL; // BlkSize Size not a multiple of 512 > 0 } - if((Size % BlkSize) != 0 || Size == 0) { + if((Size % BlkSize) != 0 || Size == 0 || Size == BlkSize) { // Size must now be atleast 2 * BlkSize (or a deadlock will occur). if(pError) { - *pError = FF_ERR_IOMAN_BAD_MEMSIZE; + *pError = FF_ERR_IOMAN_BAD_MEMSIZE | FF_CREATEIOMAN; } return NULL; // Memory Size not a multiple of BlkSize > 0 } - pIoman = (FF_IOMAN *) FF_Malloc(sizeof(FF_IOMAN)); + pIoman = (FF_IOMAN *) FF_MALLOC(sizeof(FF_IOMAN)); if(!pIoman) { // Ensure malloc() succeeded. if(pError) { - *pError = FF_ERR_NOT_ENOUGH_MEMORY; + *pError = FF_ERR_NOT_ENOUGH_MEMORY | FF_CREATEIOMAN; } return NULL; } + memset (pIoman, '\0', sizeof(FF_IOMAN)); + // This is just a bit-mask, to use a byte to keep track of memory. // pIoman->MemAllocation = 0x00; // Unset all allocation identifiers. - pIoman->pBlkDevice = NULL; - pIoman->pBuffers = NULL; - pIoman->pCacheMem = NULL; - pIoman->pPartition = NULL; - pIoman->pSemaphore = NULL; - - pIoman->pPartition = (FF_PARTITION *) FF_Malloc(sizeof(FF_PARTITION)); - if(pIoman->pPartition) { // If succeeded, flag that allocation. - pIoman->MemAllocation |= FF_IOMAN_ALLOC_PART; - pIoman->pPartition->LastFreeCluster = 0; - pIoman->pPartition->PartitionMounted = FF_FALSE; // This should be checked by FF_Open(); -#ifdef FF_PATH_CACHE - pIoman->pPartition->PCIndex = 0; - for(i = 0; i < FF_PATH_CACHE_DEPTH; i++) { - pIoman->pPartition->PathCache[i].DirCluster = 0; - pIoman->pPartition->PathCache[i].Path[0] = '\0'; -#ifdef FF_HASH_TABLE_SUPPORT - pIoman->pPartition->PathCache[i].pHashTable = FF_CreateHashTable(); - pIoman->pPartition->PathCache[i].bHashed = FF_FALSE; -#endif + pIoman->pPartition = (FF_PARTITION *) FF_MALLOC(sizeof(FF_PARTITION)); + if(!pIoman->pPartition) { + if(pError) { + *pError = FF_ERR_NOT_ENOUGH_MEMORY | FF_CREATEIOMAN; } + FF_DestroyIOMAN(pIoman); + return NULL; + } + memset (pIoman->pPartition, '\0', sizeof(FF_PARTITION)); + + pIoman->MemAllocation |= FF_IOMAN_ALLOC_PART; // If succeeded, flag that allocation. + pIoman->pPartition->LastFreeCluster = 0; + pIoman->pPartition->PartitionMounted = FF_FALSE; // This should be checked by FF_Open(); +#ifdef FF_PATH_CACHE + pIoman->pPartition->PCIndex = 0; + for(i = 0; i < FF_PATH_CACHE_DEPTH; i++) { + pIoman->pPartition->PathCache[i].DirCluster = 0; + pIoman->pPartition->PathCache[i].Path[0] = '\0'; +/*#ifdef FF_HASH_TABLE_SUPPORT + pIoman->pPartition->PathCache[i].pHashTable = FF_CreateHashTable(); + pIoman->pPartition->PathCache[i].bHashed = FF_FALSE; +#endif*/ + } #endif - } else { + +#ifdef FF_HASH_CACHE + for(i = 0; i < FF_HASH_CACHE_DEPTH; i++) { + pIoman->HashCache[i].pHashTable = FF_CreateHashTable(); + pIoman->HashCache[i].ulDirCluster = 0; + pIoman->HashCache[i].ulMisses = 100; + } +#endif + + pIoman->pBlkDevice = (FF_BLK_DEVICE *) FF_MALLOC(sizeof(FF_BLK_DEVICE)); + if(!pIoman->pBlkDevice) { // If succeeded, flag that allocation. + if(pError) { + *pError = FF_ERR_NOT_ENOUGH_MEMORY | FF_CREATEIOMAN; + } FF_DestroyIOMAN(pIoman); return NULL; } + memset (pIoman->pBlkDevice, '\0', sizeof(FF_BLK_DEVICE)); + pIoman->MemAllocation |= FF_IOMAN_ALLOC_BLKDEV; - pIoman->pBlkDevice = (FF_BLK_DEVICE *) FF_Malloc(sizeof(FF_BLK_DEVICE)); - if(pIoman->pBlkDevice) { // If succeeded, flag that allocation. - pIoman->MemAllocation |= FF_IOMAN_ALLOC_BLKDEV; - - // Make sure all pointers are NULL - pIoman->pBlkDevice->fnReadBlocks = NULL; - pIoman->pBlkDevice->fnWriteBlocks = NULL; - pIoman->pBlkDevice->pParam = NULL; - - } else { - FF_DestroyIOMAN(pIoman); - return NULL; - } + // Make sure all pointers are NULL + pIoman->pBlkDevice->fnpReadBlocks = NULL; + pIoman->pBlkDevice->fnpWriteBlocks = NULL; + pIoman->pBlkDevice->pParam = NULL; // Organise the memory provided, or create our own! if(pCacheMem) { pIoman->pCacheMem = pCacheMem; }else { // No-Cache buffer provided (malloc) - pLong = (FF_T_UINT32 *) FF_Malloc(Size); + pLong = (FF_T_UINT32 *) FF_MALLOC(Size); pIoman->pCacheMem = (FF_T_UINT8 *) pLong; if(!pIoman->pCacheMem) { - pIoman->MemAllocation |= FF_IOMAN_ALLOC_BUFFERS; + if(pError) { + *pError = FF_ERR_NOT_ENOUGH_MEMORY | FF_CREATEIOMAN; + } FF_DestroyIOMAN(pIoman); return NULL; } + pIoman->MemAllocation |= FF_IOMAN_ALLOC_BUFFERS; } + memset (pIoman->pCacheMem, '\0', Size); pIoman->BlkSize = BlkSize; pIoman->CacheSize = (FF_T_UINT16) (Size / BlkSize); @@ -163,18 +180,27 @@ FF_IOMAN *FF_CreateIOMAN(FF_T_UINT8 *pCacheMem, FF_T_UINT32 Size, FF_T_UINT16 Bl /* Malloc() memory for buffer objects. (FullFAT never refers to a buffer directly but uses buffer objects instead. Allows us to provide thread safety. */ - pIoman->pBuffers = (FF_BUFFER *) FF_Malloc(sizeof(FF_BUFFER) * pIoman->CacheSize); + pIoman->pBuffers = (FF_BUFFER *) FF_MALLOC(sizeof(FF_BUFFER) * pIoman->CacheSize); - if(pIoman->pBuffers) { - pIoman->MemAllocation |= FF_IOMAN_ALLOC_BUFDESCR; - FF_IOMAN_InitBufferDescriptors(pIoman); - } else { + if(!pIoman->pBuffers) { + if(pError) { + *pError = FF_ERR_NOT_ENOUGH_MEMORY | FF_CREATEIOMAN; + } FF_DestroyIOMAN(pIoman); + return NULL; // HT added } + memset (pIoman->pBuffers, '\0', sizeof(FF_BUFFER) * pIoman->CacheSize); + + pIoman->MemAllocation |= FF_IOMAN_ALLOC_BUFDESCR; + FF_IOMAN_InitBufferDescriptors(pIoman); // Finally create a Semaphore for Buffer Description modifications. pIoman->pSemaphore = FF_CreateSemaphore(); +#ifdef FF_BLKDEV_USES_SEM + pIoman->pBlkDevSemaphore = FF_CreateSemaphore(); +#endif + return pIoman; // Sucess, return the created object. } @@ -189,38 +215,54 @@ FF_IOMAN *FF_CreateIOMAN(FF_T_UINT8 *pCacheMem, FF_T_UINT32 Size, FF_T_UINT16 Bl **/ FF_ERROR FF_DestroyIOMAN(FF_IOMAN *pIoman) { +#ifdef FF_HASH_CACHE + FF_T_UINT32 i; +#endif + // Ensure no NULL pointer was provided. if(!pIoman) { - return FF_ERR_NULL_POINTER; + return FF_ERR_NULL_POINTER | FF_DESTROYIOMAN; } // Ensure pPartition pointer was allocated. if((pIoman->MemAllocation & FF_IOMAN_ALLOC_PART)) { - FF_Free(pIoman->pPartition); + FF_FREE(pIoman->pPartition); } // Ensure pBlkDevice pointer was allocated. if((pIoman->MemAllocation & FF_IOMAN_ALLOC_BLKDEV)) { - FF_Free(pIoman->pBlkDevice); + FF_FREE(pIoman->pBlkDevice); } // Ensure pBuffers pointer was allocated. if((pIoman->MemAllocation & FF_IOMAN_ALLOC_BUFDESCR)) { - FF_Free(pIoman->pBuffers); + FF_FREE(pIoman->pBuffers); } // Ensure pCacheMem pointer was allocated. if((pIoman->MemAllocation & FF_IOMAN_ALLOC_BUFFERS)) { - FF_Free(pIoman->pCacheMem); + FF_FREE(pIoman->pCacheMem); } // Destroy any Semaphore that was created. if(pIoman->pSemaphore) { FF_DestroySemaphore(pIoman->pSemaphore); } +#ifdef FF_BLKDEV_USES_SEM + if(pIoman->pBlkDevSemaphore) { + FF_DestroySemaphore(pIoman->pBlkDevSemaphore); + } +#endif + + // Destroy HashCache +#ifdef FF_HASH_CACHE + for(i = 0; i < FF_HASH_CACHE_DEPTH; i++) { + FF_DestroyHashTable(pIoman->HashCache[i].pHashTable); + } +#endif // Finally free the FF_IOMAN object. - FF_Free(pIoman); + FF_FREE(pIoman); return FF_ERR_NONE; } @@ -236,100 +278,13 @@ static void FF_IOMAN_InitBufferDescriptors(FF_IOMAN *pIoman) { FF_T_UINT16 i; FF_BUFFER *pBuffer = pIoman->pBuffers; pIoman->LastReplaced = 0; + // HT : it is assmued that pBuffer was cleared by memset () for(i = 0; i < pIoman->CacheSize; i++) { - pBuffer->Mode = 0; - pBuffer->NumHandles = 0; - pBuffer->Persistance = 0; - pBuffer->LRU = 0; - pBuffer->Sector = 0; pBuffer->pBuffer = (FF_T_UINT8 *)((pIoman->pCacheMem) + (pIoman->BlkSize * i)); - pBuffer->Modified = FF_FALSE; - pBuffer->Valid = FF_FALSE; pBuffer++; } } -/** - * @private - * @brief Tests the Mode for validity. - * - * @param Mode Mode of buffer to check. - * - * @return FF_TRUE when valid, else FF_FALSE. - **/ -/*static FF_T_BOOL FF_IOMAN_ModeValid(FF_T_UINT8 Mode) { - if(Mode == FF_MODE_READ || Mode == FF_MODE_WRITE) { - return FF_TRUE; - } - return FF_FALSE; -}*/ - - -/** - * @private - * @brief Fills a buffer with the appropriate sector via the device driver. - * - * @param pIoman FF_IOMAN object. - * @param Sector LBA address of the sector to fetch. - * @param pBuffer Pointer to a byte-wise buffer to store the fetched data. - * - * @return FF_TRUE when valid, else FF_FALSE. - **/ -static FF_ERROR FF_IOMAN_FillBuffer(FF_IOMAN *pIoman, FF_T_UINT32 Sector, FF_T_UINT8 *pBuffer) { - FF_T_SINT32 retVal = 0; - if(pIoman->pBlkDevice->fnReadBlocks) { // Make sure we don't execute a NULL. - do{ - retVal = pIoman->pBlkDevice->fnReadBlocks(pBuffer, Sector, 1, pIoman->pBlkDevice->pParam); - if(retVal == FF_ERR_DRIVER_BUSY) { - FF_Sleep(FF_DRIVER_BUSY_SLEEP); - } - } while(retVal == FF_ERR_DRIVER_BUSY); - if(retVal < 0) { - return -1; // FF_ERR_DRIVER_FATAL_ERROR was returned Fail! - } else { - if(retVal == 1) { - return 0; // 1 Block was sucessfully read. - } else { - return -1; // 0 Blocks we're read, Error! - } - } - } - return -1; // error no device diver registered. -} - - -/** - * @private - * @brief Flushes a buffer to the device driver. - * - * @param pIoman FF_IOMAN object. - * @param Sector LBA address of the sector to fetch. - * @param pBuffer Pointer to a byte-wise buffer to store the fetched data. - * - * @return FF_TRUE when valid, else FF_FALSE. - **/ -static FF_ERROR FF_IOMAN_FlushBuffer(FF_IOMAN *pIoman, FF_T_UINT32 Sector, FF_T_UINT8 *pBuffer) { - FF_T_SINT32 retVal = 0; - if(pIoman->pBlkDevice->fnWriteBlocks) { // Make sure we don't execute a NULL. - do{ - retVal = pIoman->pBlkDevice->fnWriteBlocks(pBuffer, Sector, 1, pIoman->pBlkDevice->pParam); - if(retVal == FF_ERR_DRIVER_BUSY) { - FF_Sleep(FF_DRIVER_BUSY_SLEEP); - } - } while(retVal == FF_ERR_DRIVER_BUSY); - if(retVal < 0) { - return -1; // FF_ERR_DRIVER_FATAL_ERROR was returned Fail! - } else { - if(retVal == 1) { - return FF_ERR_NONE; // 1 Block was sucessfully written. - } else { - return -1; // 0 Blocks we're written, Error! - } - } - } - return -1; // error no device diver registered. -} - /** * @private @@ -344,7 +299,7 @@ FF_ERROR FF_FlushCache(FF_IOMAN *pIoman) { FF_T_UINT16 i,x; if(!pIoman) { - return FF_ERR_NULL_POINTER; + return FF_ERR_NULL_POINTER | FF_FLUSHCACHE; } FF_PendSemaphore(pIoman->pSemaphore); @@ -352,7 +307,7 @@ FF_ERROR FF_FlushCache(FF_IOMAN *pIoman) { for(i = 0; i < pIoman->CacheSize; i++) { if((pIoman->pBuffers + i)->NumHandles == 0 && (pIoman->pBuffers + i)->Modified == FF_TRUE) { - FF_IOMAN_FlushBuffer(pIoman, (pIoman->pBuffers + i)->Sector, (pIoman->pBuffers + i)->pBuffer); + FF_BlockWrite(pIoman, (pIoman->pBuffers + i)->Sector, 1, (pIoman->pBuffers + i)->pBuffer); // Buffer has now been flushed, mark it as a read buffer and unmodified. (pIoman->pBuffers + i)->Mode = FF_MODE_READ; @@ -375,13 +330,6 @@ FF_ERROR FF_FlushCache(FF_IOMAN *pIoman) { return FF_ERR_NONE; } -/*static FF_T_BOOL FF_isFATSector(FF_IOMAN *pIoman, FF_T_UINT32 Sector) { - if(Sector >= pIoman->pPartition->FatBeginLBA && Sector < (pIoman->pPartition->FatBeginLBA + pIoman->pPartition->ReservedSectors)) { - return FF_TRUE; - } - return FF_FALSE; -}*/ - FF_BUFFER *FF_GetBuffer(FF_IOMAN *pIoman, FF_T_UINT32 Sector, FF_T_UINT8 Mode) { FF_BUFFER *pBuffer; FF_BUFFER *pBufLRU = NULL; @@ -393,35 +341,13 @@ FF_BUFFER *FF_GetBuffer(FF_IOMAN *pIoman, FF_T_UINT32 Sector, FF_T_UINT8 Mode) { while(!pBufMatch) { FF_PendSemaphore(pIoman->pSemaphore); { - for(i = 0; i < pIoman->CacheSize; i++) { + pBuffer = pIoman->pBuffers; + // HT if a perfect match has priority, find that first + for(i = 0; i < pIoman->CacheSize; i++, pBuffer++) { pBuffer = (pIoman->pBuffers + i); if(pBuffer->Sector == Sector && pBuffer->Valid == FF_TRUE) { pBufMatch = pBuffer; - } else { - if(pBuffer->NumHandles == 0) { - pBuffer->LRU += 1; - - if(!pBufLRU) { - pBufLRU = pBuffer; - } - if(!pBufLHITS) { - pBufLHITS = pBuffer; - } - - if(pBuffer->LRU >= pBufLRU->LRU) { - if(pBuffer->LRU == pBufLRU->LRU) { - if(pBuffer->Persistance > pBufLRU->Persistance) { - pBufLRU = pBuffer; - } - } else { - pBufLRU = pBuffer; - } - } - - if(pBuffer->Persistance < pBufLHITS->Persistance) { - pBufLHITS = pBuffer; - } - } + break; // Why look further if you found a perfect match? } } @@ -454,11 +380,38 @@ FF_BUFFER *FF_GetBuffer(FF_IOMAN *pIoman, FF_T_UINT32 Sector, FF_T_UINT8 Mode) { pBufMatch = NULL; // Sector is already in use, keep yielding until its available! } else { - // Choose a suitable buffer! + pBuffer = pIoman->pBuffers; + for(i = 0; i < pIoman->CacheSize; i++, pBuffer++) { + if(pBuffer->NumHandles == 0) { + pBuffer->LRU += 1; + + if(!pBufLRU) { + pBufLRU = pBuffer; + } + if(!pBufLHITS) { + pBufLHITS = pBuffer; + } + + if(pBuffer->LRU >= pBufLRU->LRU) { + if(pBuffer->LRU == pBufLRU->LRU) { + if(pBuffer->Persistance > pBufLRU->Persistance) { + pBufLRU = pBuffer; + } + } else { + pBufLRU = pBuffer; + } + } + + if(pBuffer->Persistance < pBufLHITS->Persistance) { + pBufLHITS = pBuffer; + } + } + } + if(pBufLRU) { // Process the suitable candidate. if(pBufLRU->Modified == FF_TRUE) { - FF_IOMAN_FlushBuffer(pIoman, pBufLRU->Sector, pBufLRU->pBuffer); + FF_BlockWrite(pIoman, pBufLRU->Sector, 1, pBufLRU->pBuffer); } pBufLRU->Mode = Mode; pBufLRU->Persistance = 1; @@ -472,7 +425,7 @@ FF_BUFFER *FF_GetBuffer(FF_IOMAN *pIoman, FF_T_UINT32 Sector, FF_T_UINT8 Mode) { pBufLRU->Modified = FF_FALSE; } - FF_IOMAN_FillBuffer(pIoman, Sector, pBufLRU->pBuffer); + FF_BlockRead(pIoman, Sector, 1, pBufLRU->pBuffer); pBufLRU->Valid = FF_TRUE; FF_ReleaseSemaphore(pIoman->pSemaphore); return pBufLRU; @@ -481,7 +434,7 @@ FF_BUFFER *FF_GetBuffer(FF_IOMAN *pIoman, FF_T_UINT32 Sector, FF_T_UINT8 Mode) { } } FF_ReleaseSemaphore(pIoman->pSemaphore); - FF_Yield(); + FF_Yield(); // Better to go asleep to give low-priority task a chance to release buffer(s) } return pBufMatch; // Return the Matched Buffer! @@ -500,7 +453,11 @@ void FF_ReleaseBuffer(FF_IOMAN *pIoman, FF_BUFFER *pBuffer) { // Protect description changes with a semaphore. FF_PendSemaphore(pIoman->pSemaphore); { - pBuffer->NumHandles--; + if (pBuffer->NumHandles) { + pBuffer->NumHandles--; + } else { + //printf ("FF_ReleaseBuffer: buffer not claimed\n"); + } } FF_ReleaseSemaphore(pIoman->pSemaphore); } @@ -522,39 +479,94 @@ void FF_ReleaseBuffer(FF_IOMAN *pIoman, FF_BUFFER *pBuffer) { **/ FF_ERROR FF_RegisterBlkDevice(FF_IOMAN *pIoman, FF_T_UINT16 BlkSize, FF_WRITE_BLOCKS fnWriteBlocks, FF_READ_BLOCKS fnReadBlocks, void *pParam) { if(!pIoman) { // We can't do anything without an IOMAN object. - return FF_ERR_NULL_POINTER; + return FF_ERR_NULL_POINTER | FF_REGISTERBLKDEVICE; } if((BlkSize % 512) != 0 || BlkSize == 0) { - return FF_ERR_IOMAN_DEV_INVALID_BLKSIZE; // BlkSize Size not a multiple of IOMAN's Expected BlockSize > 0 + return FF_ERR_IOMAN_DEV_INVALID_BLKSIZE | FF_REGISTERBLKDEVICE; // BlkSize Size not a multiple of IOMAN's Expected BlockSize > 0 } if((BlkSize % pIoman->BlkSize) != 0 || BlkSize == 0) { - return FF_ERR_IOMAN_DEV_INVALID_BLKSIZE; // BlkSize Size not a multiple of IOMAN's Expected BlockSize > 0 + return FF_ERR_IOMAN_DEV_INVALID_BLKSIZE | FF_REGISTERBLKDEVICE; // BlkSize Size not a multiple of IOMAN's Expected BlockSize > 0 } // Ensure that a device cannot be re-registered "mid-flight" // Doing so would corrupt the context of FullFAT - if(pIoman->pBlkDevice->fnReadBlocks) { - return FF_ERR_IOMAN_DEV_ALREADY_REGD; + if(pIoman->pBlkDevice->fnpReadBlocks) { + return FF_ERR_IOMAN_DEV_ALREADY_REGD | FF_REGISTERBLKDEVICE; } - if(pIoman->pBlkDevice->fnWriteBlocks) { - return FF_ERR_IOMAN_DEV_ALREADY_REGD; + if(pIoman->pBlkDevice->fnpWriteBlocks) { + return FF_ERR_IOMAN_DEV_ALREADY_REGD | FF_REGISTERBLKDEVICE; } if(pIoman->pBlkDevice->pParam) { - return FF_ERR_IOMAN_DEV_ALREADY_REGD; + return FF_ERR_IOMAN_DEV_ALREADY_REGD | FF_REGISTERBLKDEVICE; } // Here we shall just set the values. // FullFAT checks before using any of these values. pIoman->pBlkDevice->devBlkSize = BlkSize; - pIoman->pBlkDevice->fnReadBlocks = fnReadBlocks; - pIoman->pBlkDevice->fnWriteBlocks = fnWriteBlocks; + pIoman->pBlkDevice->fnpReadBlocks = fnReadBlocks; + pIoman->pBlkDevice->fnpWriteBlocks = fnWriteBlocks; pIoman->pBlkDevice->pParam = pParam; return FF_ERR_NONE; // Success } +/* + New Interface for FullFAT to read blocks. +*/ + +FF_T_SINT32 FF_BlockRead(FF_IOMAN *pIoman, FF_T_UINT32 ulSectorLBA, FF_T_UINT32 ulNumSectors, void *pBuffer) { + FF_T_SINT32 slRetVal = 0; + + if(pIoman->pPartition->TotalSectors) { + if((ulSectorLBA + ulNumSectors) > (pIoman->pPartition->TotalSectors + pIoman->pPartition->BeginLBA)) { + return -(FF_ERR_IOMAN_OUT_OF_BOUNDS_READ | FF_BLOCKREAD); + } + } + + if(pIoman->pBlkDevice->fnpReadBlocks) { // Make sure we don't execute a NULL. +#ifdef FF_BLKDEV_USES_SEM + FF_PendSemaphore(pIoman->pBlkDevSemaphore); +#endif + slRetVal = pIoman->pBlkDevice->fnpReadBlocks(pBuffer, ulSectorLBA, ulNumSectors, pIoman->pBlkDevice->pParam); +#ifdef FF_BLKDEV_USES_SEM + FF_ReleaseSemaphore(pIoman->pBlkDevSemaphore); +#endif + if(FF_GETERROR(slRetVal) == FF_ERR_DRIVER_BUSY) { + FF_Sleep(FF_DRIVER_BUSY_SLEEP); + } + } while(FF_GETERROR(slRetVal) == FF_ERR_DRIVER_BUSY); + + return slRetVal; +} + +FF_T_SINT32 FF_BlockWrite(FF_IOMAN *pIoman, FF_T_UINT32 ulSectorLBA, FF_T_UINT32 ulNumSectors, void *pBuffer) { + FF_T_SINT32 slRetVal = 0; + + if(pIoman->pPartition->TotalSectors) { + if((ulSectorLBA + ulNumSectors) > (pIoman->pPartition->TotalSectors + pIoman->pPartition->BeginLBA)) { + return -(FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_BLOCKWRITE); + } + } + + if(pIoman->pBlkDevice->fnpWriteBlocks) { // Make sure we don't execute a NULL. +#ifdef FF_BLKDEV_USES_SEM + FF_PendSemaphore(pIoman->pBlkDevSemaphore); +#endif + slRetVal = pIoman->pBlkDevice->fnpWriteBlocks(pBuffer, ulSectorLBA, ulNumSectors, pIoman->pBlkDevice->pParam); +#ifdef FF_BLKDEV_USES_SEM + FF_ReleaseSemaphore(pIoman->pBlkDevSemaphore); +#endif + if(FF_GETERROR(slRetVal) == FF_ERR_DRIVER_BUSY) { + FF_Sleep(FF_DRIVER_BUSY_SLEEP); + } + } while(FF_GETERROR(slRetVal) == FF_ERR_DRIVER_BUSY); + + return slRetVal; +} + + /** * @private **/ @@ -620,7 +632,7 @@ static FF_ERROR FF_DetermineFatType(FF_IOMAN *pIoman) { testLong = FF_getLong(pBuffer->pBuffer, 0x0000); } FF_ReleaseBuffer(pIoman, pBuffer); - if((testLong & 0x0FFFFFF8) != 0x0FFFFFF8) { + if((testLong & 0x0FFFFFF8) != 0x0FFFFFF8 && (testLong & 0x0FFFFFF8) != 0x0FFFFFF0) { return FF_ERR_IOMAN_NOT_FAT_FORMATTED; } #endif @@ -630,6 +642,119 @@ static FF_ERROR FF_DetermineFatType(FF_IOMAN *pIoman) { return FF_ERR_IOMAN_NOT_FAT_FORMATTED; } + +static FF_T_SINT8 FF_PartitionCount (FF_T_UINT8 *pBuffer) +{ + FF_T_SINT8 count = 0; + FF_T_SINT8 part; + // Check PBR or MBR signature + if (FF_getChar(pBuffer, FF_FAT_MBR_SIGNATURE) != 0x55 && + FF_getChar(pBuffer, FF_FAT_MBR_SIGNATURE) != 0xAA ) { + // No MBR, but is it a PBR ? + if (FF_getChar(pBuffer, 0) == 0xEB && // PBR Byte 0 + FF_getChar(pBuffer, 2) == 0x90 && // PBR Byte 2 + (FF_getChar(pBuffer, 21) & 0xF0) == 0xF0) {// PBR Byte 21 : Media byte + return 1; // No MBR but PBR exist then only one partition + } + return 0; // No MBR and no PBR then no partition found + } + for (part = 0; part < 4; part++) { + FF_T_UINT8 active = FF_getChar(pBuffer, FF_FAT_PTBL + FF_FAT_PTBL_ACTIVE + (16 * part)); + FF_T_UINT8 part_id = FF_getChar(pBuffer, FF_FAT_PTBL + FF_FAT_PTBL_ID + (16 * part)); + // The first sector must be a MBR, then check the partition entry in the MBR + if (active != 0x80 && (active != 0 || part_id == 0)) { + break; + } + count++; + } + return count; +} + +/* + Mount GPT Partition Tables +*/ + +#define FF_GPT_HEAD_ENTRY_SIZE 0x54 +#define FF_GPT_HEAD_TOTAL_ENTRIES 0x50 +#define FF_GPT_HEAD_PART_ENTRY_LBA 0x48 +#define FF_GPT_ENTRY_FIRST_SECTOR_LBA 0x20 +#define FF_GPT_HEAD_CRC 0x10 +#define FF_GPT_HEAD_LENGTH 0x0C + +static FF_ERROR FF_GetEfiPartitionEntry(FF_IOMAN *pIoman, FF_T_UINT32 ulPartitionNumber) { + // Continuing on from FF_MountPartition() pPartition->BeginLBA should be the sector of the GPT Header + FF_BUFFER *pBuffer; + FF_PARTITION *pPart = pIoman->pPartition; + + FF_T_UINT32 ulBeginGPT; + FF_T_UINT32 ulEntrySector; + FF_T_UINT32 ulSectorOffset; + FF_T_UINT32 ulTotalPartitionEntries; + FF_T_UINT32 ulPartitionEntrySize; + FF_T_UINT32 ulGPTHeadCRC, ulGPTCrcCheck, ulGPTHeadLength; + + if(ulPartitionNumber >= 128) { + return FF_ERR_IOMAN_INVALID_PARTITION_NUM; + } + + pBuffer = FF_GetBuffer(pIoman, pPart->BeginLBA, FF_MODE_READ); + { + if(!pBuffer) { + return FF_ERR_DEVICE_DRIVER_FAILED; + } + + // Verify this is an EFI header + if(memcmp(pBuffer->pBuffer, "EFI PART", 8) != 0) { + FF_ReleaseBuffer(pIoman, pBuffer); + return FF_ERR_IOMAN_INVALID_FORMAT; + } + + ulBeginGPT = FF_getLong(pBuffer->pBuffer, FF_GPT_HEAD_PART_ENTRY_LBA); + ulTotalPartitionEntries = FF_getLong(pBuffer->pBuffer, FF_GPT_HEAD_TOTAL_ENTRIES); + ulPartitionEntrySize = FF_getLong(pBuffer->pBuffer, FF_GPT_HEAD_ENTRY_SIZE); + ulGPTHeadCRC = FF_getLong(pBuffer->pBuffer, FF_GPT_HEAD_CRC); + ulGPTHeadLength = FF_getLong(pBuffer->pBuffer, FF_GPT_HEAD_LENGTH); + + // Calculate Head CRC + + // Blank CRC field + FF_putLong(pBuffer->pBuffer, FF_GPT_HEAD_CRC, 0x00000000); + + // Calculate CRC + ulGPTCrcCheck = FF_GetCRC32(pBuffer->pBuffer, ulGPTHeadLength); + + // Restore The CRC field + FF_putLong(pBuffer->pBuffer, FF_GPT_HEAD_CRC, ulGPTHeadCRC); + } + FF_ReleaseBuffer(pIoman, pBuffer); + + // Check CRC + if(ulGPTHeadCRC != ulGPTCrcCheck) { + return FF_ERR_IOMAN_GPT_HEADER_CORRUPT; + } + + // Calculate Sector Containing the Partition Entry we want to use. + + ulEntrySector = ((ulPartitionNumber * ulPartitionEntrySize) / pIoman->BlkSize) + ulBeginGPT; + ulSectorOffset = (ulPartitionNumber % (pIoman->BlkSize / ulPartitionEntrySize)) * ulPartitionEntrySize; + + pBuffer = FF_GetBuffer(pIoman, ulEntrySector, FF_MODE_READ); + { + if(!pBuffer) { + return FF_ERR_DEVICE_DRIVER_FAILED; + } + + pPart->BeginLBA = FF_getLong(pBuffer->pBuffer, ulSectorOffset + FF_GPT_ENTRY_FIRST_SECTOR_LBA); + } + FF_ReleaseBuffer(pIoman, pBuffer); + + if(!pPart->BeginLBA) { + return FF_ERR_IOMAN_INVALID_PARTITION_NUM; + } + + return FF_ERR_NONE; +} + /** * @public * @brief Mounts the Specified partition, the volume specified by the FF_IOMAN object provided. @@ -651,31 +776,67 @@ static FF_ERROR FF_DetermineFatType(FF_IOMAN *pIoman) { FF_ERROR FF_MountPartition(FF_IOMAN *pIoman, FF_T_UINT8 PartitionNumber) { FF_PARTITION *pPart; FF_BUFFER *pBuffer = 0; + FF_ERROR Error; + + FF_T_UINT8 ucPartitionType; + + int partCount; if(!pIoman) { return FF_ERR_NULL_POINTER; } - if(PartitionNumber > 3) { + /*if(PartitionNumber > 3) { return FF_ERR_IOMAN_INVALID_PARTITION_NUM; - } + }*/ pPart = pIoman->pPartition; + memset (pIoman->pBuffers, '\0', sizeof(FF_BUFFER) * pIoman->CacheSize); + memset (pIoman->pCacheMem, '\0', pIoman->BlkSize * pIoman->CacheSize); + + FF_IOMAN_InitBufferDescriptors(pIoman); + pIoman->FirstFile = 0; + pBuffer = FF_GetBuffer(pIoman, 0, FF_MODE_READ); if(!pBuffer) { return FF_ERR_DEVICE_DRIVER_FAILED; } + + partCount = FF_PartitionCount (pBuffer->pBuffer); + pPart->BlkSize = FF_getShort(pBuffer->pBuffer, FF_FAT_BYTES_PER_SECTOR); - if((pPart->BlkSize % 512) == 0 && pPart->BlkSize > 0) { + if (partCount == 0) { //(pPart->BlkSize % 512) == 0 && pPart->BlkSize > 0) { // Volume is not partitioned (MBR Found) pPart->BeginLBA = 0; } else { - // Primary Partitions to deal with! - pPart->BeginLBA = FF_getLong(pBuffer->pBuffer, (FF_T_UINT16)(FF_FAT_PTBL + FF_FAT_PTBL_LBA + (16 * PartitionNumber))); + + ucPartitionType = FF_getChar(pBuffer->pBuffer, FF_FAT_PTBL + FF_FAT_PTBL_ID); // Ensure its not an EFI partition! + + if(ucPartitionType != 0xEE) { + + if(PartitionNumber > 3) { + FF_ReleaseBuffer(pIoman, pBuffer); + return FF_ERR_IOMAN_INVALID_PARTITION_NUM; + } + + // Primary Partitions to deal with! + pPart->BeginLBA = FF_getLong(pBuffer->pBuffer, FF_FAT_PTBL + FF_FAT_PTBL_LBA + (16 * PartitionNumber)); + } + FF_ReleaseBuffer(pIoman, pBuffer); + if(ucPartitionType == 0xEE) { + + pPart->BeginLBA = FF_getLong(pBuffer->pBuffer, FF_FAT_PTBL + FF_FAT_PTBL_LBA); + Error = FF_GetEfiPartitionEntry(pIoman, PartitionNumber); + + if(Error) { + return Error; + } + } + if(!pPart->BeginLBA) { return FF_ERR_IOMAN_NO_MOUNTABLE_PARTITION; } @@ -690,6 +851,7 @@ FF_ERROR FF_MountPartition(FF_IOMAN *pIoman, FF_T_UINT8 PartitionNumber) { return FF_ERR_IOMAN_INVALID_FORMAT; } } + // Assume FAT16, then we'll adjust if its FAT32 pPart->ReservedSectors = FF_getShort(pBuffer->pBuffer, FF_FAT_RESERVED_SECTORS); pPart->FatBeginLBA = pPart->BeginLBA + pPart->ReservedSectors; @@ -709,6 +871,7 @@ FF_ERROR FF_MountPartition(FF_IOMAN *pIoman, FF_T_UINT8 PartitionNumber) { if(pPart->TotalSectors == 0) { pPart->TotalSectors = FF_getLong(pBuffer->pBuffer, FF_FAT_32_TOTAL_SECTORS); } + memcpy (pPart->VolLabel, pBuffer->pBuffer + FF_FAT_32_VOL_LABEL, sizeof pPart->VolLabel); } else { // FAT16 pPart->ClusterBeginLBA = pPart->BeginLBA + pPart->ReservedSectors + (pPart->NumFATS * pPart->SectorsPerFAT); pPart->TotalSectors = (FF_T_UINT32) FF_getShort(pBuffer->pBuffer, FF_FAT_16_TOTAL_SECTORS); @@ -716,16 +879,29 @@ FF_ERROR FF_MountPartition(FF_IOMAN *pIoman, FF_T_UINT8 PartitionNumber) { if(pPart->TotalSectors == 0) { pPart->TotalSectors = FF_getLong(pBuffer->pBuffer, FF_FAT_32_TOTAL_SECTORS); } + memcpy (pPart->VolLabel, pBuffer->pBuffer + FF_FAT_16_VOL_LABEL, sizeof pPart->VolLabel); } FF_ReleaseBuffer(pIoman, pBuffer); // Release the buffer finally! + + if(!pPart->BlkSize) { + return FF_ERR_IOMAN_INVALID_FORMAT; + } + pPart->RootDirSectors = ((FF_getShort(pBuffer->pBuffer, FF_FAT_ROOT_ENTRY_COUNT) * 32) + pPart->BlkSize - 1) / pPart->BlkSize; pPart->FirstDataSector = pPart->ClusterBeginLBA + pPart->RootDirSectors; pPart->DataSectors = pPart->TotalSectors - (pPart->ReservedSectors + (pPart->NumFATS * pPart->SectorsPerFAT) + pPart->RootDirSectors); + + if(!pPart->SectorsPerCluster) { + return FF_ERR_IOMAN_INVALID_FORMAT; + } + pPart->NumClusters = pPart->DataSectors / pPart->SectorsPerCluster; - if(FF_DetermineFatType(pIoman)) { - return FF_ERR_IOMAN_NOT_FAT_FORMATTED; + Error = FF_DetermineFatType(pIoman); + + if(Error) { + return Error; } #ifdef FF_MOUNT_FIND_FREE @@ -761,8 +937,8 @@ FF_ERROR FF_UnregisterBlkDevice(FF_IOMAN *pIoman) { { if(pIoman->pPartition->PartitionMounted == FF_FALSE) { pIoman->pBlkDevice->devBlkSize = 0; - pIoman->pBlkDevice->fnReadBlocks = NULL; - pIoman->pBlkDevice->fnWriteBlocks = NULL; + pIoman->pBlkDevice->fnpReadBlocks = NULL; + pIoman->pBlkDevice->fnpWriteBlocks = NULL; pIoman->pBlkDevice->pParam = NULL; } else { RetVal = FF_ERR_IOMAN_PARTITION_MOUNTED; @@ -817,7 +993,11 @@ FF_ERROR FF_UnmountPartition(FF_IOMAN *pIoman) { { if(!FF_ActiveHandles(pIoman)) { if(pIoman->FirstFile == NULL) { + // Release Semaphore to call this function! + FF_ReleaseSemaphore(pIoman->pSemaphore); FF_FlushCache(pIoman); // Flush any unwritten sectors to disk. + // Reclaim Semaphore + FF_PendSemaphore(pIoman->pSemaphore); pIoman->pPartition->PartitionMounted = FF_FALSE; } else { RetVal = FF_ERR_IOMAN_ACTIVE_HANDLES; @@ -834,12 +1014,17 @@ FF_ERROR FF_UnmountPartition(FF_IOMAN *pIoman) { FF_ERROR FF_IncreaseFreeClusters(FF_IOMAN *pIoman, FF_T_UINT32 Count) { + FF_ERROR Error; //FF_PendSemaphore(pIoman->pSemaphore); //{ if(!pIoman->pPartition->FreeClusterCount) { - pIoman->pPartition->FreeClusterCount = FF_CountFreeClusters(pIoman); + pIoman->pPartition->FreeClusterCount = FF_CountFreeClusters(pIoman, &Error); + if(Error) { + return Error; + } + } else { + pIoman->pPartition->FreeClusterCount += Count; } - pIoman->pPartition->FreeClusterCount += Count; //} //FF_ReleaseSemaphore(pIoman->pSemaphore); @@ -848,12 +1033,18 @@ FF_ERROR FF_IncreaseFreeClusters(FF_IOMAN *pIoman, FF_T_UINT32 Count) { FF_ERROR FF_DecreaseFreeClusters(FF_IOMAN *pIoman, FF_T_UINT32 Count) { + FF_ERROR Error; + //FF_lockFAT(pIoman); //{ if(!pIoman->pPartition->FreeClusterCount) { - pIoman->pPartition->FreeClusterCount = FF_CountFreeClusters(pIoman); + pIoman->pPartition->FreeClusterCount = FF_CountFreeClusters(pIoman, &Error); + if(Error) { + return Error; + } + } else { + pIoman->pPartition->FreeClusterCount -= Count; } - pIoman->pPartition->FreeClusterCount -= Count; //} //FF_unlockFAT(pIoman); diff --git a/lib/3rdparty/fullfat/ff_memory.c b/lib/3rdparty/fullfat/ff_memory.c index cdbb2acf02d..2d6913d64d7 100644 --- a/lib/3rdparty/fullfat/ff_memory.c +++ b/lib/3rdparty/fullfat/ff_memory.c @@ -48,87 +48,55 @@ #include "ff_memory.h" #include "ff_config.h" -#ifdef FF_LITTLE_ENDIAN - -/** - * @public - * @brief 8 bit memory access routines. - **/ /* - These functions swap the byte-orders of shorts and longs. A getChar function is provided - incase there is a system that doesn't have byte-wise access to all memory. + * HT inlined these functions + * + * Not much left for the C-module + */ - These functions can be replaced with your own platform specific byte-order swapping routines - for more efficiency. - The provided functions should work on almost all platforms. -*/ -FF_T_UINT8 FF_getChar(FF_T_UINT8 *pBuffer, FF_T_UINT16 offset) { - return (FF_T_UINT8) (pBuffer[offset]); +#ifndef FF_INLINE_MEMORY_ACCESS +FF_T_UINT8 FF_getChar(FF_T_UINT8 *pBuffer, FF_T_UINT32 aOffset) { + return (FF_T_UINT8) (pBuffer[aOffset]); } -FF_T_UINT16 FF_getShort(FF_T_UINT8 *pBuffer, FF_T_UINT16 offset) { - return (FF_T_UINT16) (pBuffer[offset] & 0x00FF) | ((FF_T_UINT16) (pBuffer[offset+1] << 8) & 0xFF00); +FF_T_UINT16 FF_getShort(FF_T_UINT8 *pBuffer, FF_T_UINT32 aOffset) { + FF_T_UN16 u16; + pBuffer += aOffset; + u16.bytes.u8_1 = pBuffer[1]; + u16.bytes.u8_0 = pBuffer[0]; + return u16.u16; } -FF_T_UINT32 FF_getLong(FF_T_UINT8 *pBuffer, FF_T_UINT16 offset) { - return (FF_T_UINT32) (pBuffer[offset] & 0x000000FF) | ((FF_T_UINT32) (pBuffer[offset+1] << 8) & 0x0000FF00) | ((FF_T_UINT32) (pBuffer[offset+2] << 16) & 0x00FF0000) | ((FF_T_UINT32) (pBuffer[offset+3] << 24) & 0xFF000000); +FF_T_UINT32 FF_getLong(FF_T_UINT8 *pBuffer, FF_T_UINT32 aOffset) { + FF_T_UN32 u32; + pBuffer += aOffset; + u32.bytes.u8_3 = pBuffer[3]; + u32.bytes.u8_2 = pBuffer[2]; + u32.bytes.u8_1 = pBuffer[1]; + u32.bytes.u8_0 = pBuffer[0]; + return u32.u32; } -void FF_putChar(FF_T_UINT8 *pBuffer, FF_T_UINT16 offset, FF_T_UINT8 Value) { - pBuffer[offset] = Value; +void FF_putChar(FF_T_UINT8 *pBuffer, FF_T_UINT32 aOffset, FF_T_UINT8 Value) { + pBuffer[aOffset] = Value; } -void FF_putShort(FF_T_UINT8 *pBuffer, FF_T_UINT16 offset, FF_T_UINT16 Value) { - FF_T_UINT8 *Val = (FF_T_UINT8 *) &Value; - pBuffer[offset] = Val[0]; - pBuffer[offset + 1] = Val[1]; +void FF_putShort(FF_T_UINT8 *pBuffer, FF_T_UINT32 aOffset, FF_T_UINT16 Value) { + FF_T_UN16 u16; + u16.u16 = Value; + pBuffer += aOffset; + pBuffer[0] = u16.bytes.u8_0; + pBuffer[1] = u16.bytes.u8_1; } -void FF_putLong(FF_T_UINT8 *pBuffer, FF_T_UINT16 offset, FF_T_UINT32 Value) { - FF_T_UINT8 *Val = (FF_T_UINT8 *) &Value; - pBuffer[offset] = Val[0]; - pBuffer[offset + 1] = Val[1]; - pBuffer[offset + 2] = Val[2]; - pBuffer[offset + 3] = Val[3]; -} - -#endif - -#ifdef FF_BIG_ENDIAN -/* - These haven't been tested or checked. They should work in theory :) - Please contact james@worm.me.uk if they don't work, and also any fix. -*/ -FF_T_UINT8 FF_getChar(FF_T_UINT8 *pBuffer, FF_T_UINT16 offset) { - return (FF_T_UINT8) (pBuffer[offset]); -} - -FF_T_UINT16 FF_getShort(FF_T_UINT8 *pBuffer, FF_T_UINT16 offset) { - return (FF_T_UINT16) ((pBuffer[offset] & 0xFF00) << 8) | ((FF_T_UINT16) (pBuffer[offset+1]) & 0x00FF); -} - -FF_T_UINT32 FF_getLong(FF_T_UINT8 *pBuffer, FF_T_UINT16 offset) { - return (FF_T_UINT32) ((pBuffer[offset] << 24) & 0xFF0000) | ((FF_T_UINT32) (pBuffer[offset+1] << 16) & 0x00FF0000) | ((FF_T_UINT32) (pBuffer[offset+2] << 8) & 0x0000FF00) | ((FF_T_UINT32) (pBuffer[offset+3]) & 0x000000FF); -} - -void FF_putChar(FF_T_UINT8 *pBuffer, FF_T_UINT16 offset, FF_T_UINT8 Value) { - pBuffer[offset] = Value; -} - -void FF_putShort(FF_T_UINT8 *pBuffer, FF_T_UINT16 offset, FF_T_UINT16 Value) { - FF_T_UINT8 *Val = (FF_T_UINT8 *) &Value; - pBuffer[offset] = Val[1]; - pBuffer[offset + 1] = Val[0]; -} - -void FF_putLong(FF_T_UINT8 *pBuffer, FF_T_UINT16 offset, FF_T_UINT32 Value) { - FF_T_UINT8 *Val = (FF_T_UINT8 *) &Value; - pBuffer[offset] = Val[3]; - pBuffer[offset + 1] = Val[2]; - pBuffer[offset + 2] = Val[1]; - pBuffer[offset + 3] = Val[0]; +void FF_putLong(FF_T_UINT8 *pBuffer, FF_T_UINT32 aOffset, FF_T_UINT32 Value) { + FF_T_UN32 u32; + u32.u32 = Value; + pBuffer += aOffset; + pBuffer[0] = u32.bytes.u8_0; + pBuffer[1] = u32.bytes.u8_1; + pBuffer[2] = u32.bytes.u8_2; + pBuffer[3] = u32.bytes.u8_3; } #endif - - diff --git a/lib/3rdparty/fullfat/ff_safety.c b/lib/3rdparty/fullfat/ff_safety.c index 9659f5a57eb..685185c07b8 100644 --- a/lib/3rdparty/fullfat/ff_safety.c +++ b/lib/3rdparty/fullfat/ff_safety.c @@ -55,50 +55,113 @@ **/ #include "ff_safety.h" // Íncludes ff_types.h +#include +#define TAG_FULLFAT 'FLUF' + +// Call your OS's CreateSemaphore function +// void *FF_CreateSemaphore(void) { - // Call your OS's CreateSemaphore function - // + PKSEMAPHORE ProcessSemaphore; - // return pointer to semaphore - return NULL; // Comment this out for your implementation. + /* Allocate some memory to store the semaphore */ + ProcessSemaphore = ExAllocatePoolWithTag(NonPagedPool, + sizeof(KSEMAPHORE), + TAG_FULLFAT); + if (ProcessSemaphore) + { + /* Initialize it */ + KeInitializeSemaphore(ProcessSemaphore, + 0, + MAXLONG); + } + + return ProcessSemaphore; } +// Call your OS's PendSemaphore with the provided pSemaphore pointer. +// +// This should block indefinitely until the Semaphore +// becomes available. (No timeout!) +// If your OS doesn't do it for you, you should sleep +// this thread until the Semaphore is available. void FF_PendSemaphore(void *pSemaphore) { - // Call your OS's PendSemaphore with the provided pSemaphore pointer. - // - // This should block indefinitely until the Semaphore - // becomes available. (No timeout!) - // If your OS doesn't do it for you, you should sleep - // this thread until the Semaphore is available. - pSemaphore = 0; + NTSTATUS Status; + + /* Sanity check */ + if (pSemaphore) + { + /* Wait for the sempaphore to become signaled */ + Status = KeWaitForSingleObject(pSemaphore, + Executive, + KernelMode, + FALSE, + NULL); + if (NT_SUCCESS(Status)) + { + if (Status != STATUS_SUCCESS) + { + // log an error? + } + } + else + { + // log an error? + } + } } +// Call your OS's ReleaseSemaphore with the provided pSemaphore pointer. +// void FF_ReleaseSemaphore(void *pSemaphore) { - // Call your OS's ReleaseSemaphore with the provided pSemaphore pointer. - // - // - pSemaphore = 0; + /* Sanity check */ + if (pSemaphore) + { + /* Increment the semaphore */ + KeReleaseSemaphore(pSemaphore, + 0, + 1, + FALSE); + } } +// Call your OS's DestroySemaphore with the provided pSemaphore pointer. +// void FF_DestroySemaphore(void *pSemaphore) { - // Call your OS's DestroySemaphore with the provided pSemaphore pointer. - // - // - pSemaphore = 0; + /* Sanity check */ + if (pSemaphore) + { + /* Free the semaphore memory */ + ExFreePoolWithTag(pSemaphore, + TAG_FULLFAT); + } } +// FIXME: what do we do with this? void FF_Yield(void) { // Call your OS's thread Yield function. // If this doesn't work, then a deadlock will occur } +// Call your OS's thread sleep function, +// Sleep for TimeMs milliseconds void FF_Sleep(FF_T_UINT32 TimeMs) { - // Call your OS's thread sleep function, - // Sleep for TimeMs milliseconds - TimeMs = 0; + LARGE_INTEGER Interval; + NTSTATUS Status; + + /* Calculate the interval */ + Interval.QuadPart = -((LONGLONG)TimeMs * 10000); + + /* Do the wait */ + Status = KeDelayExecutionThread(KernelMode, + FALSE, + &Interval); + if (!NT_SUCCESS(Status)) + { + // log an error? + } } diff --git a/lib/3rdparty/fullfat/ff_string.c b/lib/3rdparty/fullfat/ff_string.c index 6913ee7082f..b6c06790ea9 100644 --- a/lib/3rdparty/fullfat/ff_string.c +++ b/lib/3rdparty/fullfat/ff_string.c @@ -42,27 +42,57 @@ #include #include +#include #include "ff_string.h" +#include "ff_error.h" + +#ifdef FF_UNICODE_SUPPORT +#include +#include +#endif /* * These will eventually be moved into a platform independent string * library. Which will be optional. (To allow the use of system specific versions). */ +#ifdef FF_UNICODE_SUPPORT + +void FF_cstrntowcs(FF_T_WCHAR *wcsDest, const FF_T_INT8 *szpSource, FF_T_UINT32 len) { + while(*szpSource && len--) { + *wcsDest++ = *szpSource++; + } + *wcsDest = '\0'; +} + +void FF_cstrtowcs(FF_T_WCHAR *wcsDest, const FF_T_INT8 *szpSource) { + while(*szpSource) { + *wcsDest++ = (FF_T_WCHAR) *szpSource++; + } + *wcsDest = '\0'; +} + +void FF_wcstocstr(FF_T_INT8 *szpDest, const FF_T_WCHAR *wcsSource) { + while(*wcsSource) { + *szpDest++ = (FF_T_INT8) *wcsSource++; + } + *szpDest = '\0'; +} + +void FF_wcsntocstr(FF_T_INT8 *szpDest, const FF_T_WCHAR *wcsSource, FF_T_UINT32 len) { + while(*wcsSource && len--) { + *szpDest++ = (FF_T_INT8) *wcsSource++; + } + *szpDest = '\0'; +} + +#endif + /** * @private * @brief Converts an ASCII string to lowercase. **/ -void FF_tolower(FF_T_INT8 *string, FF_T_UINT32 strLen) { - FF_T_UINT32 i; - for(i = 0; i < strLen; i++) { - if(string[i] >= 'A' && string[i] <= 'Z') - string[i] += 32; - if(string[i] == '\0') - break; - } -} - +#ifndef FF_UNICODE_SUPPORT /** * @private * @brief Converts an ASCII string to uppercase. @@ -76,6 +106,32 @@ void FF_toupper(FF_T_INT8 *string, FF_T_UINT32 strLen) { break; } } +void FF_tolower(FF_T_INT8 *string, FF_T_UINT32 strLen) { + FF_T_UINT32 i; + for(i = 0; i < strLen; i++) { + if(string[i] >= 'A' && string[i] <= 'Z') + string[i] += 32; + if(string[i] == '\0') + break; + } +} + +#else +void FF_toupper(FF_T_WCHAR *string, FF_T_UINT32 strLen) { + FF_T_UINT32 i; + for(i = 0; i < strLen; i++) { + string[i] = towupper(string[i]); + } +} +void FF_tolower(FF_T_WCHAR *string, FF_T_UINT32 strLen) { + FF_T_UINT32 i; + for(i = 0; i < strLen; i++) { + string[i] = towlower(string[i]); + } +} +#endif + + /** @@ -84,6 +140,8 @@ void FF_toupper(FF_T_INT8 *string, FF_T_UINT32 strLen) { * otherwise FF_FALSE is returned. * **/ + +#ifndef FF_UNICODE_SUPPORT FF_T_BOOL FF_strmatch(const FF_T_INT8 *str1, const FF_T_INT8 *str2, FF_T_UINT16 len) { register FF_T_UINT16 i; register FF_T_INT8 char1, char2; @@ -112,12 +170,38 @@ FF_T_BOOL FF_strmatch(const FF_T_INT8 *str1, const FF_T_INT8 *str2, FF_T_UINT16 return FF_TRUE; } +#else + +FF_T_BOOL FF_strmatch(const FF_T_WCHAR *str1, const FF_T_WCHAR *str2, FF_T_UINT16 len) { + register FF_T_UINT16 i; + register FF_T_WCHAR char1, char2; + + if(!len) { + if(wcslen(str1) != wcslen(str2)) { + return FF_FALSE; + } + len = (FF_T_UINT16) wcslen(str1); + } + + for(i = 0; i < len; i++) { + char1 = towlower(str1[i]); + char2 = towlower(str2[i]); + if(char1 != char2) { + return FF_FALSE; + } + } + + return FF_TRUE; +} +#endif /** * @private * @brief A re-entrant Strtok function. No documentation is provided :P * Use at your own risk. (This is for FullFAT's use only). **/ + +#ifndef FF_UNICODE_SUPPORT FF_T_INT8 *FF_strtok(const FF_T_INT8 *string, FF_T_INT8 *token, FF_T_UINT16 *tokenNumber, FF_T_BOOL *last, FF_T_UINT16 Length) { FF_T_UINT16 strLen = Length; FF_T_UINT16 i,y, tokenStart, tokenEnd = 0; @@ -153,20 +237,80 @@ FF_T_INT8 *FF_strtok(const FF_T_INT8 *string, FF_T_INT8 *token, FF_T_UINT16 *tok } tokenEnd = i; } - - memcpy(token, (string + tokenStart), (FF_T_UINT32)(tokenEnd - tokenStart)); - token[tokenEnd - tokenStart] = '\0'; + if((tokenEnd - tokenStart) < FF_MAX_FILENAME) { + memcpy(token, (string + tokenStart), (FF_T_UINT32)(tokenEnd - tokenStart)); + token[tokenEnd - tokenStart] = '\0'; + } else { + memcpy(token, (string + tokenStart), (FF_T_UINT32)(FF_MAX_FILENAME)); + token[FF_MAX_FILENAME-1] = '\0'; + } + //token[tokenEnd - tokenStart] = '\0'; *tokenNumber += 1; return token; } +#else +FF_T_WCHAR *FF_strtok(const FF_T_WCHAR *string, FF_T_WCHAR *token, FF_T_UINT16 *tokenNumber, FF_T_BOOL *last, FF_T_UINT16 Length) { + FF_T_UINT16 strLen = Length; + FF_T_UINT16 i,y, tokenStart, tokenEnd = 0; -FF_T_BOOL FF_wildcompare(const FF_T_INT8 *pszWildCard, const FF_T_INT8 *pszString) { - /* Check to see if the string contains the wild card */ + i = 0; + y = 0; + + if(string[i] == '\\' || string[i] == '/') { + i++; + } + + tokenStart = i; + + while(i < strLen) { + if(string[i] == '\\' || string[i] == '/') { + y++; + if(y == *tokenNumber) { + tokenStart = (FF_T_UINT16)(i + 1); + } + if(y == (*tokenNumber + 1)) { + tokenEnd = i; + break; + } + } + i++; + } + + if(!tokenEnd) { + if(*last == FF_TRUE) { + return NULL; + } else { + *last = FF_TRUE; + } + tokenEnd = i; + } + if((tokenEnd - tokenStart) < FF_MAX_FILENAME) { + memcpy(token, (string + tokenStart), (FF_T_UINT32)(tokenEnd - tokenStart) * sizeof(FF_T_WCHAR)); + token[tokenEnd - tokenStart] = '\0'; + } else { + memcpy(token, (string + tokenStart), (FF_T_UINT32)(FF_MAX_FILENAME) * sizeof(FF_T_WCHAR)); + token[FF_MAX_FILENAME-1] = '\0'; + } + //token[tokenEnd - tokenStart] = '\0'; + *tokenNumber += 1; + + return token; +} +#endif + +/* + A Wild-Card Comparator Library function, Provided by Adam Fullerton. + This can be extended or altered to improve or advance wildCard matching + of the FF_FindFirst() and FF_FindNext() API's. +*/ +#ifdef FF_FINDAPI_ALLOW_WILDCARDS +/*FF_T_BOOL FF_wildcompare(const FF_T_INT8 *pszWildCard, const FF_T_INT8 *pszString) { + // Check to see if the string contains the wild card if (!memchr(pszWildCard, '*', strlen(pszWildCard))) { - /* if it does not then do a straight string compare */ + // if it does not then do a straight string compare if (strcmp(pszWildCard, pszString)) { return FF_FALSE; @@ -177,20 +321,20 @@ FF_T_BOOL FF_wildcompare(const FF_T_INT8 *pszWildCard, const FF_T_INT8 *pszStrin while ((*pszWildCard) && (*pszString)) { - /* Test for the wild card */ + // Test for the wild card if (*pszWildCard == '*') { - /* Eat more than one */ + // Eat more than one while (*pszWildCard == '*') { pszWildCard++; } - /* If there are more chars in the string */ + // If there are more chars in the string if (*pszWildCard) { - /* Search for the next char */ + // Search for the next char pszString = memchr(pszString, (int)*pszWildCard, strlen(pszString)); - /* if it does not exist then the strings don't match */ + // if it does not exist then the strings don't match if (!pszString) { return FF_FALSE; @@ -201,7 +345,7 @@ FF_T_BOOL FF_wildcompare(const FF_T_INT8 *pszWildCard, const FF_T_INT8 *pszStrin { if (*pszWildCard) { - /* continue */ + // continue break; } else @@ -212,17 +356,17 @@ FF_T_BOOL FF_wildcompare(const FF_T_INT8 *pszWildCard, const FF_T_INT8 *pszStrin } else { - /* Fail if they don't match */ + // Fail if they don't match if (*pszWildCard != *pszString) { return FF_FALSE; } } - /* Bump both pointers */ + // Bump both pointers pszWildCard++; pszString++; } - /* fail if different lengths */ + // fail if different lengths if (*pszWildCard != *pszString) { return FF_FALSE; @@ -230,5 +374,83 @@ FF_T_BOOL FF_wildcompare(const FF_T_INT8 *pszWildCard, const FF_T_INT8 *pszStrin } return FF_TRUE; -} +}*/ +/* + This is a better Wild-card compare function, that works perfectly, and is much more efficient. + This function was contributed by one of our commercial customers. +*/ +#ifdef FF_UNICODE_SUPPORT +FF_T_BOOL FF_wildcompare(const FF_T_WCHAR *pszWildCard, const FF_T_WCHAR *pszString) { + register const FF_T_WCHAR *pszWc = NULL; + register const FF_T_WCHAR *pszStr = NULL; // Encourage the string pointers to be placed in memory. + do { + if ( *pszWildCard == '*' ) { + while(*(1 + pszWildCard++) == '*'); // Eat up multiple '*''s + pszWc = (pszWildCard - 1); + pszStr = pszString; + } + if (*pszWildCard == '?' && !*pszString) { + return FF_FALSE; // False when the string is ended, yet a ? charachter is demanded. + } +#ifdef FF_WILDCARD_CASE_INSENSITIVE + if (*pszWildCard != '?' && tolower(*pszWildCard) != tolower(*pszString)) { +#else + if (*pszWildCard != '?' && *pszWildCard != *pszString) { +#endif + if (pszWc == NULL) { + return FF_FALSE; + } + pszWildCard = pszWc; + pszString = pszStr++; + } + } while ( *pszWildCard++ && *pszString++ ); + while(*pszWildCard == '*') { + pszWildCard++; + } + + if(!*(pszWildCard - 1)) { // WildCard is at the end. (Terminated) + return FF_TRUE; // Therefore this must be a match. + } + + return FF_FALSE; // If not, then return FF_FALSE! +} +#else +FF_T_BOOL FF_wildcompare(const FF_T_INT8 *pszWildCard, const FF_T_INT8 *pszString) { + register const FF_T_INT8 *pszWc = NULL; + register const FF_T_INT8 *pszStr = NULL; // Encourage the string pointers to be placed in memory. + do { + if ( *pszWildCard == '*' ) { + while(*(1 + pszWildCard++) == '*'); // Eat up multiple '*''s + pszWc = (pszWildCard - 1); + pszStr = pszString; + } + if (*pszWildCard == '?' && !*pszString) { + return FF_FALSE; // False when the string is ended, yet a ? charachter is demanded. + } +#ifdef FF_WILDCARD_CASE_INSENSITIVE + if (*pszWildCard != '?' && tolower(*pszWildCard) != tolower(*pszString)) { +#else + if (*pszWildCard != '?' && *pszWildCard != *pszString) { +#endif + if (pszWc == NULL) { + return FF_FALSE; + } + pszWildCard = pszWc; + pszString = pszStr++; + } + } while ( *pszWildCard++ && *pszString++ ); + + while(*pszWildCard == '*') { + pszWildCard++; + } + + if(!*(pszWildCard - 1)) { // WildCard is at the end. (Terminated) + return FF_TRUE; // Therefore this must be a match. + } + + return FF_FALSE; // If not, then return FF_FALSE! +} +#endif + +#endif diff --git a/lib/3rdparty/fullfat/ff_unicode.c b/lib/3rdparty/fullfat/ff_unicode.c new file mode 100644 index 00000000000..24fffd420d4 --- /dev/null +++ b/lib/3rdparty/fullfat/ff_unicode.c @@ -0,0 +1,294 @@ +/***************************************************************************** + * FullFAT - High Performance, Thread-Safe Embedded FAT File-System * + * Copyright (C) 2009 James Walmsley (james@worm.me.uk) * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + * * + * IMPORTANT NOTICE: * + * ================= * + * Alternative Licensing is available directly from the Copyright holder, * + * (James Walmsley). For more information consult LICENSING.TXT to obtain * + * a Commercial license. * + * * + * See RESTRICTIONS.TXT for extra restrictions on the use of FullFAT. * + * * + * Removing the above notice is illegal and will invalidate this license. * + ***************************************************************************** + * See http://worm.me.uk/fullfat for more information. * + * Or http://fullfat.googlecode.com/ for latest releases and the wiki. * + *****************************************************************************/ + +/** + * @file ff_unicode.c + * @author James Walmsley + * @ingroup UNICODE + * + * @defgroup UNICODE FullFAT UNICODE Library + * @brief Portable UNICODE Transformation Library for FullFAT + * + **/ + +#include "ff_unicode.h" +#include "string.h" + +// UTF-8 Routines + +/* + UCS-4 range (hex.) UTF-8 octet sequence (binary) + 0000 0000-0000 007F 0xxxxxxx + 0000 0080-0000 07FF 110xxxxx 10xxxxxx + 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx + + 0001 0000-001F FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + 0020 0000-03FF FFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx -- We don't encode these because we won't receive them. (Invalid UNICODE). + 0400 0000-7FFF FFFF 1111110x 10xxxxxx ... 10xxxxxx -- We don't encode these because we won't receive them. (Invalid UNICODE). +*/ + +FF_T_UINT FF_GetUtf16SequenceLen(FF_T_UINT16 usLeadChar) { + if((usLeadChar & 0xFC00) == 0xD800) { + return 2; + } + return 1; +} + +/* + Returns the number of UTF-8 units read. + Will not exceed ulSize UTF-16 units. (ulSize * 2 bytes). +*/ +/* + UCS-4 range (hex.) UTF-8 octet sequence (binary) + 0000 0000-0000 007F 0xxxxxxx + 0000 0080-0000 07FF 110xxxxx 10xxxxxx + 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx + + 0001 0000-001F FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + 0020 0000-03FF FFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx -- We don't encode these because we won't receive them. (Invalid UNICODE). + 0400 0000-7FFF FFFF 1111110x 10xxxxxx ... 10xxxxxx -- We don't encode these because we won't receive them. (Invalid UNICODE). +*/ +FF_T_SINT32 FF_Utf8ctoUtf16c(FF_T_UINT16 *utf16Dest, const FF_T_UINT8 *utf8Source, FF_T_UINT32 ulSize) { + FF_T_UINT32 ulUtf32char; + FF_T_UINT16 utf16Source = 0; + register FF_T_INT uiSequenceNumber = 0; + + while((*utf8Source & (0x80 >> (uiSequenceNumber)))) { // Count number of set bits before a zero. + uiSequenceNumber++; + } + + if(!uiSequenceNumber) { + uiSequenceNumber++; + } + + if(!ulSize) { + return FF_ERR_UNICODE_DEST_TOO_SMALL; + } + + switch(uiSequenceNumber) { + case 1: + utf16Source = (FF_T_UINT16) *utf8Source; + memcpy(utf16Dest,&utf16Source,sizeof(FF_T_UINT16)); + //bobtntfullfat *utf16Dest = (FF_T_UINT16) *utf8Source; + break; + + case 2: + utf16Source =(FF_T_UINT16) ((*utf8Source & 0x1F) << 6) | ((*(utf8Source + 1) & 0x3F)); + memcpy(utf16Dest,&utf16Source,sizeof(FF_T_UINT16)); + //bobtntfullfat *utf16Dest = (FF_T_UINT16) ((*utf8Source & 0x1F) << 6) | ((*(utf8Source + 1) & 0x3F)); + break; + + case 3: + utf16Source =(FF_T_UINT16) ((*utf8Source & 0x0F) << 12) | ((*(utf8Source + 1) & 0x3F) << 6) | ((*(utf8Source + 2) & 0x3F)); + memcpy(utf16Dest,&utf16Source,sizeof(FF_T_UINT16)); + //bobtntfullfat *utf16Dest = (FF_T_UINT16) ((*utf8Source & 0x0F) << 12) | ((*(utf8Source + 1) & 0x3F) << 6) | ((*(utf8Source + 2) & 0x3F)); + break; + + case 4: + // Convert to UTF-32 and then into UTF-16 + if(ulSize < 2) { + return FF_ERR_UNICODE_DEST_TOO_SMALL; + } + ulUtf32char = (FF_T_UINT16) ((*utf8Source & 0x0F) << 18) | ((*(utf8Source + 1) & 0x3F) << 12) | ((*(utf8Source + 2) & 0x3F) << 6) | ((*(utf8Source + 3) & 0x3F)); + + utf16Source = (FF_T_UINT16) (((ulUtf32char - 0x10000) & 0xFFC00) >> 10) | 0xD800; + memcpy(utf16Dest,&utf16Source,sizeof(FF_T_UINT16)); + utf16Source = (FF_T_UINT16) (((ulUtf32char - 0x10000) & 0x003FF) >> 00) | 0xDC00; + memcpy(utf16Dest+1,&utf16Source,sizeof(FF_T_UINT16)); + //bobtntfullfat *(utf16Dest + 0) = (FF_T_UINT16) (((ulUtf32char - 0x10000) & 0xFFC00) >> 10) | 0xD800; + //bobtntfullfat *(utf16Dest + 1) = (FF_T_UINT16) (((ulUtf32char - 0x10000) & 0x003FF) >> 00) | 0xDC00; + break; + + default: + break; + } + + return uiSequenceNumber; +} + + +/* + Returns the number of UTF-8 units required to encode the UTF-16 sequence. + Will not exceed ulSize UTF-8 units. (ulSize * 1 bytes). +*/ +FF_T_SINT32 FF_Utf16ctoUtf8c(FF_T_UINT8 *utf8Dest, const FF_T_UINT16 *utf16Source, FF_T_UINT32 ulSize) { + FF_T_UINT32 ulUtf32char; + FF_T_UINT16 ulUtf16char; + + if(!ulSize) { + return FF_ERR_UNICODE_DEST_TOO_SMALL; + } + + memcpy(&ulUtf16char, utf16Source, sizeof(FF_T_UINT16)); + if((/*bobtntfullfat *utf16Source*/ulUtf16char & 0xF800) == 0xD800) { // A surrogate sequence was encountered. Must transform to UTF32 first. + ulUtf32char = ((FF_T_UINT32) (ulUtf16char & 0x003FF) << 10) + 0x10000; + //bobtntfullfat ulUtf32char = ((FF_T_UINT32) (*(utf16Source + 0) & 0x003FF) << 10) + 0x10000; + + memcpy(&ulUtf16char, utf16Source + 1, sizeof(FF_T_UINT16)); + if((/*bobtntfullfat *(utf16Source + 1)*/ulUtf16char & 0xFC00) != 0xDC00) { + return FF_ERR_UNICODE_INVALID_SEQUENCE; // Invalid UTF-16 sequence. + } + ulUtf32char |= ((FF_T_UINT32) (/*bobtntfullfat *(utf16Source + 1)*/ulUtf16char & 0x003FF)); + + } else { + ulUtf32char = (FF_T_UINT32) /*bobtntfullfat *utf16Source*/ulUtf16char; + } + + // Now convert to the UTF-8 sequence. + if(ulUtf32char < 0x00000080) { // Single byte UTF-8 sequence. + *(utf8Dest + 0) = (FF_T_UINT8) ulUtf32char; + return 1; + } + + if(ulUtf32char < 0x00000800) { // Double byte UTF-8 sequence. + if(ulSize < 2) { + return FF_ERR_UNICODE_DEST_TOO_SMALL; + } + *(utf8Dest + 0) = (FF_T_UINT8) (0xC0 | ((ulUtf32char >> 6) & 0x1F)); + *(utf8Dest + 1) = (FF_T_UINT8) (0x80 | ((ulUtf32char >> 0) & 0x3F)); + return 2; + } + + if(ulUtf32char < 0x00010000) { // Triple byte UTF-8 sequence. + if(ulSize < 3) { + return FF_ERR_UNICODE_DEST_TOO_SMALL; + } + *(utf8Dest + 0) = (FF_T_UINT8) (0xE0 | ((ulUtf32char >> 12) & 0x0F)); + *(utf8Dest + 1) = (FF_T_UINT8) (0x80 | ((ulUtf32char >> 6 ) & 0x3F)); + *(utf8Dest + 2) = (FF_T_UINT8) (0x80 | ((ulUtf32char >> 0 ) & 0x3F)); + return 3; + } + + if(ulUtf32char < 0x00200000) { // Quadruple byte UTF-8 sequence. + if(ulSize < 4) { + return FF_ERR_UNICODE_DEST_TOO_SMALL; + } + *(utf8Dest + 0) = (FF_T_UINT8) (0xF0 | ((ulUtf32char >> 18) & 0x07)); + *(utf8Dest + 1) = (FF_T_UINT8) (0x80 | ((ulUtf32char >> 12) & 0x3F)); + *(utf8Dest + 2) = (FF_T_UINT8) (0x80 | ((ulUtf32char >> 6 ) & 0x3F)); + *(utf8Dest + 3) = (FF_T_UINT8) (0x80 | ((ulUtf32char >> 0 ) & 0x3F)); + return 4; + } + + return FF_ERR_UNICODE_INVALID_CODE; // Invalid Charachter +} + + +// UTF-16 Support Functions + +// Converts a UTF-32 Charachter into its equivalent UTF-16 sequence. +FF_T_SINT32 FF_Utf32ctoUtf16c(FF_T_UINT16 *utf16Dest, FF_T_UINT32 utf32char, FF_T_UINT32 ulSize) { + + // Check that its a valid UTF-32 wide-char! + + if(utf32char >= 0xD800 && utf32char <= 0xDFFF) { // This range is not a valid Unicode code point. + return FF_ERR_UNICODE_INVALID_CODE; // Invalid charachter. + } + + if(utf32char < 0x10000) { + *utf16Dest = (FF_T_UINT16) utf32char; // Simple conversion! Char comes within UTF-16 space (without surrogates). + return 1; + } + + if(ulSize < 2) { + return FF_ERR_UNICODE_DEST_TOO_SMALL; // Not enough UTF-16 units to record this charachter. + } + + if(utf32char < 0x00200000) { + // Conversion to a UTF-16 Surrogate pair! + //valueImage = utf32char - 0x10000; + + *(utf16Dest + 0) = (FF_T_UINT16) (((utf32char - 0x10000) & 0xFFC00) >> 10) | 0xD800; + *(utf16Dest + 1) = (FF_T_UINT16) (((utf32char - 0x10000) & 0x003FF) >> 00) | 0xDC00; + + return 2; // Surrogate pair encoded value. + } + + return FF_ERR_UNICODE_INVALID_CODE; // Invalid Charachter +} + +// Converts a UTF-16 sequence into its equivalent UTF-32 code point. +FF_T_SINT32 FF_Utf16ctoUtf32c(FF_T_UINT32 *utf32Dest, const FF_T_UINT16 *utf16Source) { + + if((*utf16Source & 0xFC00) != 0xD800) { // Not a surrogate sequence. + *utf32Dest = (FF_T_UINT32) *utf16Source; + return 1; // A single UTF-16 item was used to represent the charachter. + } + + *utf32Dest = ((FF_T_UINT32) (*(utf16Source + 0) & 0x003FF) << 10) + 0x10000; + + if((*(utf16Source + 1) & 0xFC00) != 0xDC00) { + return FF_ERR_UNICODE_INVALID_SEQUENCE; // Invalid UTF-16 sequence. + } + *utf32Dest |= ((FF_T_UINT32) (*(utf16Source + 1) & 0x003FF)); + return 2; // 2 utf-16 units make up the Unicode code-point. +} + + +/* + Returns the total number of UTF-16 items required to represent + the provided UTF-32 string in UTF-16 form. +*/ +/* +FF_T_UINT FF_Utf32GetUtf16Len(const FF_T_UINT32 *utf32String) { + FF_T_UINT utf16len = 0; + + while(*utf32String) { + if(*utf32String++ <= 0xFFFF) { + utf16len++; + } else { + utf16len += 2; + } + } + + return utf16len; +}*/ + + +// String conversions + +FF_T_SINT32 FF_Utf32stoUtf8s(FF_T_UINT8 *Utf8String, FF_T_UINT32 *Utf32String) { + int i = 0,y = 0; + + FF_T_UINT16 utf16buffer[2]; + + while(Utf32String[i]) { + // Convert to a UTF16 char. + FF_Utf32ctoUtf16c(utf16buffer, Utf32String[i], 2); + // Now convert the UTF16 to UTF8 sequence. + y += FF_Utf16ctoUtf8c(&Utf8String[y], utf16buffer, 4); + i++; + } + + Utf8String[y] = '\0'; + + return 0; +} diff --git a/lib/rtl/image.c b/lib/rtl/image.c index 03c402fc20c..ce54a6b4df9 100644 --- a/lib/rtl/image.c +++ b/lib/rtl/image.c @@ -46,6 +46,7 @@ LdrVerifyMappedImageMatchesChecksum( IN ULONG ImageSize, IN ULONG FileLength) { +#if 0 PIMAGE_NT_HEADERS Header; PUSHORT Ptr; ULONG Sum; @@ -118,6 +119,9 @@ LdrVerifyMappedImageMatchesChecksum( DPRINT1("Image %p checksum mismatches! 0x%x != 0x%x, ImageSize %x, FileLen %x\n", BaseAddress, CalcSum, HeaderSum, ImageSize, FileLength); return (BOOLEAN)(CalcSum == HeaderSum); +#else + return TRUE; +#endif } /* diff --git a/ntoskrnl/ke/apc.c b/ntoskrnl/ke/apc.c index 53f19f1a271..c4bab2a4c02 100644 --- a/ntoskrnl/ke/apc.c +++ b/ntoskrnl/ke/apc.c @@ -340,6 +340,9 @@ KiDeliverApc(IN KPROCESSOR_MODE DeliveryMode, break; } + /* Kernel APC is not pending anymore */ + Thread->ApcState.KernelApcPending = FALSE; + /* Get the next Entry */ ApcListEntry = Thread->ApcState.ApcListHead[KernelMode].Flink; Apc = CONTAINING_RECORD(ApcListEntry, KAPC, ApcListEntry); diff --git a/ntoskrnl/mm/ARM3/sysldr.c b/ntoskrnl/mm/ARM3/sysldr.c index 443a33d5e63..2ca28005d9c 100644 --- a/ntoskrnl/mm/ARM3/sysldr.c +++ b/ntoskrnl/mm/ARM3/sysldr.c @@ -1059,7 +1059,7 @@ MiResolveImageReferences(IN PVOID ImageBase, { /* It's not, it's importing stuff it shouldn't be! */ MiDereferenceImports(LoadedImports); - if (LoadedImports) ExFreePool(LoadedImports); + if (LoadedImports) ExFreePoolWithTag(LoadedImports, 'TDmM'); return STATUS_PROCEDURE_NOT_FOUND; } @@ -1073,7 +1073,7 @@ MiResolveImageReferences(IN PVOID ImageBase, { /* This is not kernel code */ MiDereferenceImports(LoadedImports); - if (LoadedImports) ExFreePool(LoadedImports); + if (LoadedImports) ExFreePoolWithTag(LoadedImports, 'TDmM'); return STATUS_PROCEDURE_NOT_FOUND; } @@ -1098,7 +1098,7 @@ MiResolveImageReferences(IN PVOID ImageBase, { /* Failed */ MiDereferenceImports(LoadedImports); - if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR); + if (LoadedImports) ExFreePoolWithTag(LoadedImports, 'TDmM'); return Status; } @@ -1219,7 +1219,7 @@ CheckDllState: /* Cleanup and return */ RtlFreeUnicodeString(&NameString); MiDereferenceImports(LoadedImports); - if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR); + if (LoadedImports) ExFreePoolWithTag(LoadedImports, 'TDmM'); return Status; } @@ -1252,7 +1252,7 @@ CheckDllState: { /* Cleanup and return */ MiDereferenceImports(LoadedImports); - if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR); + if (LoadedImports) ExFreePoolWithTag(LoadedImports, 'TDmM'); DPRINT1("Warning: Driver failed to load, %S not found\n", *MissingDriver); return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND; } @@ -1282,7 +1282,7 @@ CheckDllState: { /* Cleanup and return */ MiDereferenceImports(LoadedImports); - if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR); + if (LoadedImports) ExFreePoolWithTag(LoadedImports, 'TDmM'); return Status; } @@ -1315,13 +1315,13 @@ CheckDllState: if (!ImportCount) { /* Free the list and set it to no imports */ - ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR); + ExFreePoolWithTag(LoadedImports, 'TDmM'); LoadedImports = MM_SYSLDR_NO_IMPORTS; } else if (ImportCount == 1) { /* Just one entry, we can free the table and only use our entry */ - ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR); + ExFreePoolWithTag(LoadedImports, 'TDmM'); LoadedImports = (PLOAD_IMPORTS)ImportEntry; } else if (ImportCount != LoadedImports->Count) @@ -1349,7 +1349,7 @@ CheckDllState: } /* Free the old copy */ - ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR); + ExFreePoolWithTag(LoadedImports, 'TDmM'); LoadedImports = NewImports; } } @@ -3004,7 +3004,7 @@ Quickie: /* if (NamePrefix) ExFreePool(PrefixName.Buffer); */ /* Free the name buffer and return status */ - ExFreePoolWithTag(Buffer, TAG_LDR_WSTR); + ExFreePoolWithTag(Buffer, 'nLmM'); return Status; } diff --git a/ntoskrnl/mm/section.c b/ntoskrnl/mm/section.c index aa092adf41d..7749a03eb05 100644 --- a/ntoskrnl/mm/section.c +++ b/ntoskrnl/mm/section.c @@ -4326,14 +4326,11 @@ MmUnmapViewOfSection(PEPROCESS Process, * and calculate the image base address */ for (i = 0; i < NrSegments; i++) { - if (!(SectionSegments[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD)) - { - if (Segment == &SectionSegments[i]) - { - ImageBaseAddress = (char*)BaseAddress - (ULONG_PTR)SectionSegments[i].VirtualAddress; - break; - } - } + if (Segment == &SectionSegments[i]) + { + ImageBaseAddress = (char*)BaseAddress - (ULONG_PTR)SectionSegments[i].VirtualAddress; + break; + } } if (i >= NrSegments) { @@ -4342,13 +4339,10 @@ MmUnmapViewOfSection(PEPROCESS Process, for (i = 0; i < NrSegments; i++) { - if (!(SectionSegments[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD)) - { - PVOID SBaseAddress = (PVOID) - ((char*)ImageBaseAddress + (ULONG_PTR)SectionSegments[i].VirtualAddress); + PVOID SBaseAddress = (PVOID) + ((char*)ImageBaseAddress + (ULONG_PTR)SectionSegments[i].VirtualAddress); - Status = MmUnmapViewOfSegment(AddressSpace, SBaseAddress); - } + Status = MmUnmapViewOfSegment(AddressSpace, SBaseAddress); } } else @@ -4571,6 +4565,7 @@ MmMapViewOfSection(IN PVOID SectionObject, PMMSUPPORT AddressSpace; ULONG ViewOffset; NTSTATUS Status = STATUS_SUCCESS; + BOOLEAN NotAtBase = FALSE; if ((ULONG_PTR)SectionObject & 1) { @@ -4624,13 +4619,10 @@ MmMapViewOfSection(IN PVOID SectionObject, ImageSize = 0; for (i = 0; i < NrSegments; i++) { - if (!(SectionSegments[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD)) - { - ULONG_PTR MaxExtent; - MaxExtent = (ULONG_PTR)SectionSegments[i].VirtualAddress + - SectionSegments[i].Length; - ImageSize = max(ImageSize, MaxExtent); - } + ULONG_PTR MaxExtent; + MaxExtent = (ULONG_PTR)SectionSegments[i].VirtualAddress + + SectionSegments[i].Length; + ImageSize = max(ImageSize, MaxExtent); } ImageSectionObject->ImageSize = ImageSize; @@ -4652,33 +4644,33 @@ MmMapViewOfSection(IN PVOID SectionObject, MmUnlockAddressSpace(AddressSpace); return(STATUS_UNSUCCESSFUL); } + /* Remember that we loaded image at a different base address */ + NotAtBase = TRUE; } for (i = 0; i < NrSegments; i++) { - if (!(SectionSegments[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD)) - { - PVOID SBaseAddress = (PVOID) - ((char*)ImageBase + (ULONG_PTR)SectionSegments[i].VirtualAddress); - MmLockSectionSegment(&SectionSegments[i]); - Status = MmMapViewOfSegment(AddressSpace, - Section, - &SectionSegments[i], - &SBaseAddress, - SectionSegments[i].Length, - SectionSegments[i].Protection, - 0, - 0); - MmUnlockSectionSegment(&SectionSegments[i]); - if (!NT_SUCCESS(Status)) - { - MmUnlockAddressSpace(AddressSpace); - return(Status); - } - } + PVOID SBaseAddress = (PVOID) + ((char*)ImageBase + (ULONG_PTR)SectionSegments[i].VirtualAddress); + MmLockSectionSegment(&SectionSegments[i]); + Status = MmMapViewOfSegment(AddressSpace, + Section, + &SectionSegments[i], + &SBaseAddress, + SectionSegments[i].Length, + SectionSegments[i].Protection, + 0, + 0); + MmUnlockSectionSegment(&SectionSegments[i]); + if (!NT_SUCCESS(Status)) + { + MmUnlockAddressSpace(AddressSpace); + return(Status); + } } *BaseAddress = (PVOID)ImageBase; + *ViewSize = ImageSize; } else { @@ -4756,7 +4748,12 @@ MmMapViewOfSection(IN PVOID SectionObject, MmUnlockAddressSpace(AddressSpace); - return(STATUS_SUCCESS); + if (NotAtBase) + Status = STATUS_IMAGE_NOT_AT_BASE; + else + Status = STATUS_SUCCESS; + + return Status; } /* diff --git a/subsystems/win32/win32k/eng/device.c b/subsystems/win32/win32k/eng/device.c index 802bcf50e4f..b20ad072db2 100644 --- a/subsystems/win32/win32k/eng/device.c +++ b/subsystems/win32/win32k/eng/device.c @@ -90,7 +90,7 @@ EngpRegisterGraphicsDevice( pustrDeviceName->Length); /* Create a win device name (FIXME: virtual devices!) */ - swprintf(pGraphicsDevice->szWinDeviceName, L"\\\\.\\VIDEO%d", (int)giDevNum); + swprintf(pGraphicsDevice->szWinDeviceName, L"\\\\.\\DISPLAY%d", (int)giDevNum); /* Allocate a buffer for the strings */ cj = pustrDiplayDrivers->Length + pustrDescription->Length + sizeof(WCHAR); diff --git a/subsystems/win32/win32k/include/focus.h b/subsystems/win32/win32k/include/focus.h index 299efb56e0f..5c7e6fcefcc 100644 --- a/subsystems/win32/win32k/include/focus.h +++ b/subsystems/win32/win32k/include/focus.h @@ -7,6 +7,10 @@ HWND FASTCALL IntGetCaptureWindow(VOID); HWND FASTCALL IntGetFocusWindow(VOID); +HWND FASTCALL +co_UserSetCapture(HWND hWnd); +BOOL FASTCALL +IntReleaseCapture(VOID); /* * These functions take the window handles from current thread queue. diff --git a/subsystems/win32/win32k/include/gdiobj.h b/subsystems/win32/win32k/include/gdiobj.h index e29077c2f42..032acc2c523 100644 --- a/subsystems/win32/win32k/include/gdiobj.h +++ b/subsystems/win32/win32k/include/gdiobj.h @@ -47,6 +47,7 @@ typedef struct _BASEOBJECT USHORT cExclusiveLock; USHORT BaseFlags; PTHREADINFO Tid; + EX_PUSH_LOCK pushlock; } BASEOBJECT, *POBJ; typedef struct _CLIENTOBJ @@ -62,8 +63,6 @@ enum BASEFLAGS BASEFLAG_READY_TO_DIE = 0x1000 }; -extern PSECTION_OBJECT GdiTableSection; - BOOL INTERNAL_CALL GDIOBJ_OwnedByCurrentProcess(HGDIOBJ ObjectHandle); BOOL INTERNAL_CALL GDIOBJ_SetOwnership(HGDIOBJ ObjectHandle, PEPROCESS Owner); BOOL INTERNAL_CALL GDIOBJ_CopyOwnership(HGDIOBJ CopyFrom, HGDIOBJ CopyTo); @@ -78,7 +77,7 @@ PGDIOBJ INTERNAL_CALL GDIOBJ_LockObj (HGDIOBJ hObj, DWORD ObjectType); PGDIOBJ INTERNAL_CALL GDIOBJ_ShareLockObj (HGDIOBJ hObj, DWORD ObjectType); VOID INTERNAL_CALL GDIOBJ_LockMultipleObjs(ULONG ulCount, IN HGDIOBJ* ahObj, OUT PGDIOBJ* apObj); -PVOID INTERNAL_CALL GDI_MapHandleTable(PSECTION_OBJECT SectionObject, PEPROCESS Process); +PVOID INTERNAL_CALL GDI_MapHandleTable(PEPROCESS Process); INIT_FUNCTION NTSTATUS diff --git a/subsystems/win32/win32k/include/monitor.h b/subsystems/win32/win32k/include/monitor.h index 280864fb7cb..cc42f0d1edb 100644 --- a/subsystems/win32/win32k/include/monitor.h +++ b/subsystems/win32/win32k/include/monitor.h @@ -40,7 +40,7 @@ NTSTATUS CleanupMonitorImpl(VOID); NTSTATUS IntAttachMonitor(PDEVOBJ *pGdiDevice, ULONG DisplayNumber); NTSTATUS IntDetachMonitor(PDEVOBJ *pGdiDevice); -NTSTATUS IntResetMonitorSize(IN PDEVOBJ *pGdiDevice); +NTSTATUS IntUpdateMonitorSize(IN PDEVOBJ *pGdiDevice); PMONITOR FASTCALL UserGetMonitorObject(IN HMONITOR); PMONITOR FASTCALL IntGetPrimaryMonitor(VOID); diff --git a/subsystems/win32/win32k/include/msgqueue.h b/subsystems/win32/win32k/include/msgqueue.h index f078a16f23d..5af589ee0a8 100644 --- a/subsystems/win32/win32k/include/msgqueue.h +++ b/subsystems/win32/win32k/include/msgqueue.h @@ -78,12 +78,16 @@ typedef struct _USER_MESSAGE_QUEUE HANDLE NewMessagesHandle; /* Last time PeekMessage() was called. */ ULONG LastMsgRead; - /* Current window with focus (ie. receives keyboard input) for this queue. */ - HWND FocusWindow; - /* Current active window for this queue. */ - HWND ActiveWindow; /* Current capture window for this queue. */ HWND CaptureWindow; + PWND spwndCapture; + /* Current window with focus (ie. receives keyboard input) for this queue. */ + HWND FocusWindow; + PWND spwndFocus; + /* Current active window for this queue. */ + HWND ActiveWindow; + PWND spwndActive; + PWND spwndActivePrev; /* Current move/size window for this queue */ HWND MoveSize; /* Current menu owner window for this queue */ @@ -92,6 +96,8 @@ typedef struct _USER_MESSAGE_QUEUE BYTE MenuState; /* Caret information for this queue */ PTHRDCARETINFO CaretInfo; + /* Message Queue Flags */ + DWORD QF_flags; /* queue state tracking */ // Send list QS_SENDMESSAGE @@ -112,8 +118,28 @@ typedef struct _USER_MESSAGE_QUEUE struct _DESKTOP *Desktop; } USER_MESSAGE_QUEUE, *PUSER_MESSAGE_QUEUE; +#define QF_UPDATEKEYSTATE 0x00000001 +#define QF_FMENUSTATUSBREAK 0x00000004 +#define QF_FMENUSTATUS 0x00000008 +#define QF_FF10STATUS 0x00000010 +#define QF_MOUSEMOVED 0x00000020 // See MouseMoved. +#define QF_ACTIVATIONCHANGE 0x00000040 +#define QF_TABSWITCHING 0x00000080 +#define QF_KEYSTATERESET 0x00000100 +#define QF_INDESTROY 0x00000200 +#define QF_LOCKNOREMOVE 0x00000400 +#define QF_FOCUSNULLSINCEACTIVE 0x00000800 +#define QF_DIALOGACTIVE 0x00004000 +#define QF_EVENTDEACTIVATEREMOVED 0x00008000 +#define QF_TRACKMOUSELEAVE 0x00020000 +#define QF_TRACKMOUSEHOVER 0x00040000 +#define QF_TRACKMOUSEFIRING 0x00080000 +#define QF_CAPTURELOCKED 0x00100000 +#define QF_ACTIVEWNDTRACKING 0x00200000 + BOOL FASTCALL MsqIsHung(PUSER_MESSAGE_QUEUE MessageQueue); +VOID CALLBACK HungAppSysTimerProc(HWND,UINT,UINT_PTR,DWORD); NTSTATUS FASTCALL co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue, HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam, diff --git a/subsystems/win32/win32k/include/window.h b/subsystems/win32/win32k/include/window.h index 0e2073d3df1..44e6a8c86db 100644 --- a/subsystems/win32/win32k/include/window.h +++ b/subsystems/win32/win32k/include/window.h @@ -111,4 +111,6 @@ VOID FASTCALL IntNotifyWinEvent(DWORD, PWND, LONG, LONG, DWORD); PWND FASTCALL co_UserCreateWindowEx(CREATESTRUCTW*, PUNICODE_STRING, PLARGE_STRING); WNDPROC FASTCALL IntGetWindowProc(PWND,BOOL); +BOOL FASTCALL IntEnableWindow(HWND,BOOL); + /* EOF */ diff --git a/subsystems/win32/win32k/main/dllmain.c b/subsystems/win32/win32k/main/dllmain.c index 1bff6e3f3b9..59853171885 100644 --- a/subsystems/win32/win32k/main/dllmain.c +++ b/subsystems/win32/win32k/main/dllmain.c @@ -107,7 +107,7 @@ Win32kProcessCallback(struct _EPROCESS *Process, if(Process->Peb != NULL) { /* map the gdi handle table to user land */ - Process->Peb->GdiSharedHandleTable = GDI_MapHandleTable(GdiTableSection, Process); + Process->Peb->GdiSharedHandleTable = GDI_MapHandleTable(Process); Process->Peb->GdiDCAttributeList = GDI_BATCH_LIMIT; } @@ -264,7 +264,7 @@ Win32kThreadCallback(struct _ETHREAD *Thread, if (Win32Thread->KeyboardLayout) pci->hKL = Win32Thread->KeyboardLayout->hkl; pci->dwTIFlags = Win32Thread->TIF_flags; /* CI may not have been initialized. */ - if (!pci->pDeskInfo && Win32Thread->pDeskInfo) + if (!pci->pDeskInfo && Win32Thread->pDeskInfo) { if (!pci->ulClientDelta) pci->ulClientDelta = DesktopHeapGetUserDelta(); diff --git a/subsystems/win32/win32k/ntuser/class.c b/subsystems/win32/win32k/ntuser/class.c index 81e0076be26..74595eccaa3 100644 --- a/subsystems/win32/win32k/ntuser/class.c +++ b/subsystems/win32/win32k/ntuser/class.c @@ -1398,6 +1398,7 @@ UserUnregisterClass(IN PUNICODE_STRING ClassName, INT UserGetClassName(IN PCLS Class, IN OUT PUNICODE_STRING ClassName, + IN RTL_ATOM Atom, IN BOOL Ansi) { NTSTATUS Status = STATUS_SUCCESS; @@ -1451,7 +1452,7 @@ UserGetClassName(IN PCLS Class, /* query the class name */ Status = RtlQueryAtomInAtomTable(gAtomTable, - Class->atomClassName, + Atom ? Atom : Class->atomClassName, NULL, NULL, szTemp, @@ -1485,7 +1486,7 @@ UserGetClassName(IN PCLS Class, /* query the atom name */ Status = RtlQueryAtomInAtomTable(gAtomTable, - Class->atomClassName, + Atom ? Atom : Class->atomClassName, NULL, NULL, ClassName->Buffer, @@ -2376,18 +2377,27 @@ NtUserGetClassInfo( INT APIENTRY NtUserGetClassName (IN HWND hWnd, - OUT PUNICODE_STRING ClassName, - IN BOOL Ansi) + IN BOOL Real, + OUT PUNICODE_STRING ClassName) { PWND Window; UNICODE_STRING CapturedClassName; - INT Ret = 0; + INT iCls, Ret = 0; + RTL_ATOM Atom = 0; UserEnterShared(); Window = UserGetWindowObject(hWnd); if (Window != NULL) { + if (Real && Window->fnid && !(Window->fnid & FNID_DESTROY)) + { + if (LookupFnIdToiCls(Window->fnid, &iCls)) + { + Atom = gpsi->atomSysClass[iCls]; + } + } + _SEH2_TRY { ProbeForWriteUnicodeString(ClassName); @@ -2396,7 +2406,8 @@ NtUserGetClassName (IN HWND hWnd, /* get the class name */ Ret = UserGetClassName(Window->pcls, &CapturedClassName, - Ansi); + Atom, + FALSE); if (Ret != 0) { diff --git a/subsystems/win32/win32k/ntuser/display.c b/subsystems/win32/win32k/ntuser/display.c index 98b93d5ddf7..76c0d25f315 100644 --- a/subsystems/win32/win32k/ntuser/display.c +++ b/subsystems/win32/win32k/ntuser/display.c @@ -766,7 +766,7 @@ UserChangeDisplaySettings( //IntvGetDeviceCaps(&PrimarySurface, &GdiHandleTable->DevCaps); /* Set new size of the monitor */ - IntResetMonitorSize(ppdev); + IntUpdateMonitorSize(ppdev); /* Remove all cursor clipping */ UserClipCursor(NULL); diff --git a/subsystems/win32/win32k/ntuser/focus.c b/subsystems/win32/win32k/ntuser/focus.c index 9989e880956..cdc26a7ff94 100644 --- a/subsystems/win32/win32k/ntuser/focus.c +++ b/subsystems/win32/win32k/ntuser/focus.c @@ -546,6 +546,9 @@ co_UserSetCapture(HWND hWnd) pti = PsGetCurrentThreadWin32Thread(); ThreadQueue = pti->MessageQueue; + if (ThreadQueue->QF_flags & QF_CAPTURELOCKED) + return NULL; + if ((Window = UserGetWindowObject(hWnd))) { if (Window->head.pti->MessageQueue != ThreadQueue) @@ -553,7 +556,7 @@ co_UserSetCapture(HWND hWnd) return NULL; } } - + hWndPrev = MsqSetStateWindow(ThreadQueue, MSQ_STATE_CAPTURE, hWnd); if (hWndPrev) @@ -563,22 +566,58 @@ co_UserSetCapture(HWND hWnd) IntNotifyWinEvent(EVENT_SYSTEM_CAPTUREEND, pWnd, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI); } - /* also remove other windows if not capturing anymore */ - if (hWnd == NULL) - { - MsqSetStateWindow(ThreadQueue, MSQ_STATE_MENUOWNER, NULL); - MsqSetStateWindow(ThreadQueue, MSQ_STATE_MOVESIZE, NULL); - } - if (Window) IntNotifyWinEvent(EVENT_SYSTEM_CAPTURESTART, Window, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI); - co_IntPostOrSendMessage(hWndPrev, WM_CAPTURECHANGED, 0, (LPARAM)hWnd); + if (hWndPrev && hWndPrev != hWnd) + { + if (ThreadQueue->MenuOwner && Window) ThreadQueue->QF_flags |= QF_CAPTURELOCKED; + + co_IntPostOrSendMessage(hWndPrev, WM_CAPTURECHANGED, 0, (LPARAM)hWnd); + + ThreadQueue->QF_flags &= ~QF_CAPTURELOCKED; + } + ThreadQueue->CaptureWindow = hWnd; + if (hWnd == NULL) // Release mode. + { + MOUSEINPUT mi; + /// These are hacks! + /* also remove other windows if not capturing anymore */ + MsqSetStateWindow(ThreadQueue, MSQ_STATE_MENUOWNER, NULL); + MsqSetStateWindow(ThreadQueue, MSQ_STATE_MOVESIZE, NULL); + /// + /* Somebody may have missed some mouse movements */ + mi.dx = 0; + mi.dy = 0; + mi.mouseData = 0; + mi.dwFlags = MOUSEEVENTF_MOVE; + mi.time = 0; + mi.dwExtraInfo = 0; + IntMouseInput(&mi); + } return hWndPrev; } +BOOL +FASTCALL +IntReleaseCapture(VOID) +{ + PTHREADINFO pti; + PUSER_MESSAGE_QUEUE ThreadQueue; + + pti = PsGetCurrentThreadWin32Thread(); + ThreadQueue = pti->MessageQueue; + + // Can not release inside WM_CAPTURECHANGED!! + if (ThreadQueue->QF_flags & QF_CAPTURELOCKED) return FALSE; + + co_UserSetCapture(NULL); + + return TRUE; +} + /* * @implemented */ diff --git a/subsystems/win32/win32k/ntuser/message.c b/subsystems/win32/win32k/ntuser/message.c index 0822009f541..31fc6ac7d7c 100644 --- a/subsystems/win32/win32k/ntuser/message.c +++ b/subsystems/win32/win32k/ntuser/message.c @@ -16,7 +16,6 @@ #include BOOLEAN NTAPI PsGetProcessExitProcessCalled(PEPROCESS Process); -HWND FASTCALL co_UserSetCapture(HWND hWnd); #define PM_BADMSGFLAGS ~((QS_RAWINPUT << 16)|PM_QS_SENDMESSAGE|PM_QS_PAINT|PM_QS_POSTMESSAGE|PM_QS_INPUT|PM_NOYIELD|PM_REMOVE) @@ -320,6 +319,7 @@ PackParam(LPARAM *lParamPacked, UINT Msg, WPARAM wParam, LPARAM lParam, BOOL Non { PMSGMEMORY MsgMemoryEntry; PVOID PackedData; + SIZE_T size; MsgMemoryEntry = FindMsgMemory(Msg); @@ -328,7 +328,13 @@ PackParam(LPARAM *lParamPacked, UINT Msg, WPARAM wParam, LPARAM lParam, BOOL Non /* Keep previous behavior */ return STATUS_SUCCESS; } - PackedData = ExAllocatePoolWithTag(NonPagedPool, MsgMemorySize(MsgMemoryEntry, wParam, lParam), TAG_MSG); + size = MsgMemorySize(MsgMemoryEntry, wParam, lParam); + if (!size) + { + DPRINT1("No size for lParamPacked\n"); + return STATUS_SUCCESS; + } + PackedData = ExAllocatePoolWithTag(NonPagedPool, size, TAG_MSG); RtlCopyMemory(PackedData, (PVOID)lParam, MsgMemorySize(MsgMemoryEntry, wParam, lParam)); *lParamPacked = (LPARAM)PackedData; } @@ -850,15 +856,18 @@ co_IntWaitMessage( PWND Window, Window, MsgFilterMin, MsgFilterMax); + if (!NT_SUCCESS(Status)) + { + SetLastNtError(Status); + DPRINT1("Exit co_IntWaitMessage on error!\n"); + return FALSE; + } + if (Status == STATUS_USER_APC || Status == STATUS_TIMEOUT) + { + return FALSE; + } } - while ( (STATUS_WAIT_0 <= Status && Status <= STATUS_WAIT_63) || - STATUS_TIMEOUT == Status ); - - if (!NT_SUCCESS(Status)) - { - SetLastNtError(Status); - DPRINT1("Exit co_IntWaitMessage on error!\n"); - } + while ( TRUE ); return FALSE; } @@ -874,6 +883,7 @@ co_IntGetPeekMessage( PMSG pMsg, PWND Window; PTHREADINFO pti; BOOL Present = FALSE; + NTSTATUS Status; if ( hWnd == HWND_TOPMOST || hWnd == HWND_BROADCAST ) hWnd = HWND_BOTTOM; @@ -932,16 +942,18 @@ co_IntGetPeekMessage( PMSG pMsg, co_HOOK_CallHooks( WH_GETMESSAGE, HC_ACTION, RemoveMsg & PM_REMOVE, (LPARAM)pMsg); - if ( bGMSG ) - { - Present = (WM_QUIT != pMsg->message); - break; - } + if ( bGMSG ) break; } if ( bGMSG ) { - if ( !co_IntWaitMessage(Window, MsgFilterMin, MsgFilterMax) ) + Status = co_MsqWaitForNewMessages( pti->MessageQueue, + Window, + MsgFilterMin, + MsgFilterMax); + if ( !NT_SUCCESS(Status) || + Status == STATUS_USER_APC || + Status == STATUS_TIMEOUT ) { Present = -1; break; @@ -1033,7 +1045,6 @@ UserPostMessage( HWND Wnd, PTHREADINFO pti; MSG Message, KernelModeMsg; LARGE_INTEGER LargeTickCount; - PMSGMEMORY MsgMemoryEntry; Message.hwnd = Wnd; Message.message = Msg; @@ -1043,11 +1054,18 @@ UserPostMessage( HWND Wnd, KeQueryTickCount(&LargeTickCount); Message.time = MsqCalculateMessageTime(&LargeTickCount); - MsgMemoryEntry = FindMsgMemory(Message.message); + if (is_pointer_message(Message.message)) + { + EngSetLastError(ERROR_MESSAGE_SYNC_ONLY ); + return FALSE; + } if( Msg >= WM_DDE_FIRST && Msg <= WM_DDE_LAST ) { NTSTATUS Status; + PMSGMEMORY MsgMemoryEntry; + + MsgMemoryEntry = FindMsgMemory(Message.message); Status = CopyMsgToKernelMem(&KernelModeMsg, &Message, MsgMemoryEntry); if (! NT_SUCCESS(Status)) @@ -1066,12 +1084,6 @@ UserPostMessage( HWND Wnd, return TRUE; } - if (is_pointer_message(Message.message)) - { - EngSetLastError(ERROR_MESSAGE_SYNC_ONLY ); - return FALSE; - } - if (!Wnd) { return UserPostThreadMessage( PtrToInt(PsGetCurrentThreadId()), @@ -1233,6 +1245,7 @@ co_IntSendMessageTimeoutSingle( HWND hWnd, if (uFlags & SMTO_ABORTIFHUNG && MsqIsHung(Window->head.pti->MessageQueue)) { + // FIXME - Set window hung and add to a list. /* FIXME - Set a LastError? */ RETURN( FALSE); } @@ -1258,14 +1271,14 @@ co_IntSendMessageTimeoutSingle( HWND hWnd, } while ((STATUS_TIMEOUT == Status) && (uFlags & SMTO_NOTIMEOUTIFNOTHUNG) && - !MsqIsHung(Window->head.pti->MessageQueue)); + !MsqIsHung(Window->head.pti->MessageQueue)); // FIXME - Set window hung and add to a list. IntCallWndProcRet( Window, hWnd, Msg, wParam, lParam, (LRESULT *)uResult); if (STATUS_TIMEOUT == Status) { - /* -MSDN says: +/* + MSDN says: Microsoft Windows 2000: If GetLastError returns zero, then the function timed out. XP+ : If the function fails or times out, the return value is zero. @@ -1348,7 +1361,13 @@ co_IntSendMessageNoWait(HWND hWnd, &Result); return Result; } - +/* MSDN: + If you send a message in the range below WM_USER to the asynchronous message + functions (PostMessage, SendNotifyMessage, and SendMessageCallback), its + message parameters cannot include pointers. Otherwise, the operation will fail. + The functions will return before the receiving thread has had a chance to + process the message and the sender will free the memory before it is used. +*/ LRESULT FASTCALL co_IntSendMessageWithCallBack( HWND hWnd, UINT Msg, @@ -1840,7 +1859,7 @@ NtUserGetMessage(PMSG pMsg, UserLeave(); - if (Ret) + if (Ret == TRUE) { _SEH2_TRY { @@ -1855,6 +1874,9 @@ NtUserGetMessage(PMSG pMsg, _SEH2_END; } + if ((INT)Ret != -1) + Ret = Ret ? (WM_QUIT != pMsg->message) : FALSE; + return Ret; } @@ -2014,24 +2036,23 @@ NtUserMessageCall( HWND hWnd, UserEnterExclusive(); - /* Validate input */ - if (hWnd && (hWnd != INVALID_HANDLE_VALUE)) - { - Window = UserGetWindowObject(hWnd); - if (!Window) - { - UserLeave(); - return FALSE; - } - } - switch(dwType) { case FNID_DEFWINDOWPROC: - if (Window) UserRefObjectCo(Window, &Ref); + /* Validate input */ + if (hWnd && (hWnd != INVALID_HANDLE_VALUE)) + { + Window = UserGetWindowObject(hWnd); + if (!Window) + { + UserLeave(); + return FALSE; + } + } + UserRefObjectCo(Window, &Ref); lResult = IntDefWindowProc(Window, Msg, wParam, lParam, Ansi); Ret = TRUE; - if (Window) UserDerefObjectCo(Window); + UserDerefObjectCo(Window); break; case FNID_SENDNOTIFYMESSAGE: Ret = UserSendNotifyMessage(hWnd, Msg, wParam, lParam); @@ -2050,7 +2071,6 @@ NtUserMessageCall( HWND hWnd, } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { - Ret = FALSE; _SEH2_YIELD(break); } _SEH2_END; @@ -2121,13 +2141,18 @@ NtUserMessageCall( HWND hWnd, } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { - Ret = FALSE; _SEH2_YIELD(break); } _SEH2_END; - if (!co_IntSendMessageWithCallBack(hWnd, Msg, wParam, lParam, - CallBackInfo.CallBack, CallBackInfo.Context, &uResult)) + if (is_pointer_message(Msg)) + { + EngSetLastError(ERROR_MESSAGE_SYNC_ONLY ); + break; + } + + if (!(Ret = co_IntSendMessageWithCallBack(hWnd, Msg, wParam, lParam, + CallBackInfo.CallBack, CallBackInfo.Context, &uResult))) { DPRINT1("Callback failure!\n"); } @@ -2165,7 +2190,6 @@ NtUserMessageCall( HWND hWnd, } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { - Ret = FALSE; _SEH2_YIELD(break); } _SEH2_END; diff --git a/subsystems/win32/win32k/ntuser/misc.c b/subsystems/win32/win32k/ntuser/misc.c index 3a6b0e3f9d3..a36403e49c1 100644 --- a/subsystems/win32/win32k/ntuser/misc.c +++ b/subsystems/win32/win32k/ntuser/misc.c @@ -179,7 +179,9 @@ NtUserGetGUIThreadInfo( GUITHREADINFO SafeGui; PDESKTOP Desktop; PUSER_MESSAGE_QUEUE MsgQueue; + PTHREADINFO W32Thread; PETHREAD Thread = NULL; + DECLARE_RETURN(BOOLEAN); DPRINT("Enter NtUserGetGUIThreadInfo\n"); @@ -198,7 +200,7 @@ NtUserGetGUIThreadInfo( RETURN( FALSE); } - if(idThread) + if (idThread) { Status = PsLookupThreadByThreadId((HANDLE)(DWORD_PTR)idThread, &Thread); if(!NT_SUCCESS(Status)) @@ -206,24 +208,17 @@ NtUserGetGUIThreadInfo( EngSetLastError(ERROR_ACCESS_DENIED); RETURN( FALSE); } - Desktop = ((PTHREADINFO)Thread->Tcb.Win32Thread)->rpdesk; + W32Thread = (PTHREADINFO)Thread->Tcb.Win32Thread; + Desktop = W32Thread->rpdesk; } else - { - /* get the foreground thread */ - PTHREADINFO W32Thread = (PTHREADINFO)PsGetCurrentThread()->Tcb.Win32Thread; + { /* get the foreground thread */ + Thread = PsGetCurrentThread(); + W32Thread = (PTHREADINFO)Thread->Tcb.Win32Thread; Desktop = W32Thread->rpdesk; - if(Desktop) - { - MsgQueue = Desktop->ActiveMessageQueue; - if(MsgQueue) - { - Thread = MsgQueue->Thread; - } - } } - if(!Thread || !Desktop) + if (!Thread || !Desktop ) { if(idThread && Thread) ObDereferenceObject(Thread); @@ -231,13 +226,21 @@ NtUserGetGUIThreadInfo( RETURN( FALSE); } - MsgQueue = (PUSER_MESSAGE_QUEUE)Desktop->ActiveMessageQueue; + if ( W32Thread->MessageQueue ) + MsgQueue = W32Thread->MessageQueue; + else + { + if ( Desktop ) MsgQueue = Desktop->ActiveMessageQueue; + } + CaretInfo = MsgQueue->CaretInfo; SafeGui.flags = (CaretInfo->Visible ? GUI_CARETBLINKING : 0); - if(MsgQueue->MenuOwner) + + if (MsgQueue->MenuOwner) SafeGui.flags |= GUI_INMENUMODE | MsgQueue->MenuState; - if(MsgQueue->MoveSize) + + if (MsgQueue->MoveSize) SafeGui.flags |= GUI_INMOVESIZE; /* FIXME add flag GUI_16BITTASK */ @@ -254,7 +257,7 @@ NtUserGetGUIThreadInfo( SafeGui.rcCaret.right = SafeGui.rcCaret.left + CaretInfo->Size.cx; SafeGui.rcCaret.bottom = SafeGui.rcCaret.top + CaretInfo->Size.cy; - if(idThread) + if (idThread) ObDereferenceObject(Thread); Status = MmCopyToCaller(lpgui, &SafeGui, sizeof(GUITHREADINFO)); diff --git a/subsystems/win32/win32k/ntuser/monitor.c b/subsystems/win32/win32k/ntuser/monitor.c index 935be89cf12..83ea41a1b9b 100644 --- a/subsystems/win32/win32k/ntuser/monitor.c +++ b/subsystems/win32/win32k/ntuser/monitor.c @@ -157,17 +157,8 @@ IntAttachMonitor(IN PDEVOBJ *pGdiDevice, } Monitor->GdiDevice = pGdiDevice; - Monitor->rcMonitor.left = 0; - Monitor->rcMonitor.top = 0; - Monitor->rcMonitor.right = Monitor->rcMonitor.left + pGdiDevice->gdiinfo.ulHorzRes; - Monitor->rcMonitor.bottom = Monitor->rcMonitor.top + pGdiDevice->gdiinfo.ulVertRes; - Monitor->rcWork = Monitor->rcMonitor; Monitor->cWndStack = 0; - Monitor->hrgnMonitor = IntSysCreateRectRgnIndirect( &Monitor->rcMonitor ); - - IntGdiSetRegionOwner(Monitor->hrgnMonitor, GDI_OBJ_HMGR_PUBLIC); - if (gMonitorList == NULL) { DPRINT("Primary monitor is beeing attached\n"); @@ -184,6 +175,8 @@ IntAttachMonitor(IN PDEVOBJ *pGdiDevice, } Monitor->Prev = p; } + + IntUpdateMonitorSize(pGdiDevice); return STATUS_SUCCESS; } @@ -246,7 +239,7 @@ IntDetachMonitor(IN PDEVOBJ *pGdiDevice) return STATUS_SUCCESS; } -/* IntResetMonitorSize +/* IntUpdateMonitorSize * * Reset size of the monitor using atached device * @@ -259,7 +252,7 @@ IntDetachMonitor(IN PDEVOBJ *pGdiDevice) * Returns a NTSTATUS */ NTSTATUS -IntResetMonitorSize(IN PDEVOBJ *pGdiDevice) +IntUpdateMonitorSize(IN PDEVOBJ *pGdiDevice) { PMONITOR Monitor; @@ -701,13 +694,10 @@ NtUserGetMonitorInfo( /* fill device name */ if (MonitorInfo.cbSize == sizeof (MONITORINFOEXW)) { - WCHAR nul = L'\0'; - INT len = Monitor->DeviceName.Length; - if (len >= CCHDEVICENAME * sizeof (WCHAR)) - len = (CCHDEVICENAME - 1) * sizeof (WCHAR); - - memcpy(MonitorInfo.szDevice, Monitor->DeviceName.Buffer, len); - memcpy(MonitorInfo.szDevice + (len / sizeof (WCHAR)), &nul, sizeof (WCHAR)); + RtlStringCbCopyNW(MonitorInfo.szDevice, + sizeof(MonitorInfo.szDevice), + Monitor->DeviceName.Buffer, + Monitor->DeviceName.Length); } /* output data */ diff --git a/subsystems/win32/win32k/ntuser/msgqueue.c b/subsystems/win32/win32k/ntuser/msgqueue.c index f225950dfd6..6af6000137c 100644 --- a/subsystems/win32/win32k/ntuser/msgqueue.c +++ b/subsystems/win32/win32k/ntuser/msgqueue.c @@ -121,7 +121,7 @@ ClearMsgBitsMask(PUSER_MESSAGE_QUEUE Queue, UINT MessageBits) pti = Queue->Thread->Tcb.Win32Thread; if (MessageBits & QS_KEY) - { + { if (--Queue->nCntsQBits[QSRosKey] == 0) ClrMask |= QS_KEY; } if (MessageBits & QS_MOUSEMOVE) // ReactOS hard coded. @@ -193,6 +193,7 @@ co_MsqInsertMouseMessage(MSG* Msg) { LARGE_INTEGER LargeTickCount; MSLLHOOKSTRUCT MouseHookData; + PDESKTOP pDesk; PWND pwnd, pwndDesktop; KeQueryTickCount(&LargeTickCount); @@ -244,10 +245,19 @@ co_MsqInsertMouseMessage(MSG* Msg) pwnd != NULL; pwnd = pwnd->spwndNext ) { - if((pwnd->style & WS_VISIBLE) && + if ( pwnd->state2 & WNDS2_INDESTROY || pwnd->state & WNDS_DESTROYED ) + { + DPRINT("The Window is in DESTROY!\n"); + continue; + } + + if((pwnd->style & WS_VISIBLE) && IntPtInWindow(pwnd, Msg->pt.x, Msg->pt.y)) { Msg->hwnd = pwnd->head.h; + pDesk = pwnd->head.rpdesk; + pDesk->htEx = HTCLIENT; + pDesk->spwndTrack = pwnd; break; } } @@ -623,7 +633,7 @@ co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue, UINT uTimeout, BOOL Block, INT HookMessage, ULONG_PTR *uResult) { - PTHREADINFO pti; + PTHREADINFO pti, ptirec; PUSER_SENT_MESSAGE Message; KEVENT CompletionEvent; NTSTATUS WaitStatus; @@ -642,8 +652,10 @@ co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue, pti = PsGetCurrentThreadWin32Thread(); ThreadQueue = pti->MessageQueue; + ptirec = MessageQueue->Thread->Tcb.Win32Thread; ASSERT(ThreadQueue != MessageQueue); - + ASSERT(ptirec->pcti); // Send must have a client side to receive it!!!! + Timeout.QuadPart = (LONGLONG) uTimeout * (LONGLONG) -10000; /* FIXME - increase reference counter of sender's message queue here */ @@ -727,7 +739,7 @@ co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue, Entry = Entry->Flink; } - DPRINT("MsqSendMessage (blocked) timed out\n"); + DPRINT("MsqSendMessage (blocked) timed out 1\n"); } while (co_MsqDispatchOneSentMessage(ThreadQueue)) ; @@ -787,7 +799,7 @@ co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue, Entry = Entry->Flink; } - DPRINT("MsqSendMessage timed out\n"); + DPRINT("MsqSendMessage timed out 2\n"); break; } while (co_MsqDispatchOneSentMessage(ThreadQueue)) @@ -860,7 +872,7 @@ static void MsqSendParentNotify( PWND pwnd, WORD event, WORD idChild, POINT pt ) if (pwndParent == pwndDesktop) break; pt.x += pwnd->rcClient.left - pwndParent->rcClient.left; pt.y += pwnd->rcClient.top - pwndParent->rcClient.top; - + pwnd = pwndParent; co_IntSendMessage( UserHMGetHandle(pwnd), WM_PARENTNOTIFY, MAKEWPARAM( event, idChild ), MAKELPARAM( pt.x, pt.y ) ); @@ -902,7 +914,7 @@ BOOL co_IntProcessMouseMessage(MSG* msg, BOOL* RemoveMessages, UINT first, UINT } DPRINT("Got mouse message for 0x%x, hittest: 0x%x\n", msg->hwnd, hittest ); - + if (pwndMsg == NULL || pwndMsg->head.pti != pti) { /* Remove and ignore the message */ @@ -972,7 +984,7 @@ BOOL co_IntProcessMouseMessage(MSG* msg, BOOL* RemoveMessages, UINT first, UINT } } - if (!((first == 0 && last == 0) || (message >= first || message <= last))) + if (!((first == 0 && last == 0) || (message >= first || message <= last))) { DPRINT("Message out of range!!!\n"); RETURN(FALSE); @@ -1023,8 +1035,6 @@ BOOL co_IntProcessMouseMessage(MSG* msg, BOOL* RemoveMessages, UINT first, UINT /* message is accepted now (but may still get dropped) */ - pti->rpdesk->htEx = hittest; /* Now set the capture hit. */ - event.message = msg->message; event.time = msg->time; event.hwnd = msg->hwnd; @@ -1095,8 +1105,8 @@ BOOL co_IntProcessMouseMessage(MSG* msg, BOOL* RemoveMessages, UINT first, UINT if (pwndTop && pwndTop != pwndDesktop) { - LONG ret = co_IntSendMessage( msg->hwnd, - WM_MOUSEACTIVATE, + LONG ret = co_IntSendMessage( msg->hwnd, + WM_MOUSEACTIVATE, (WPARAM)UserHMGetHandle(pwndTop), MAKELONG( hittest, msg->message)); switch(ret) @@ -1250,7 +1260,7 @@ co_MsqPeekHardwareMessage(IN PUSER_MESSAGE_QUEUE MessageQueue, CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE, ListEntry); - do + do { if (IsListEmpty(CurrentEntry)) break; if (!CurrentMessage) break; @@ -1296,7 +1306,7 @@ MsqPeekMessage(IN PUSER_MESSAGE_QUEUE MessageQueue, PLIST_ENTRY CurrentEntry; PUSER_MESSAGE CurrentMessage; PLIST_ENTRY ListHead; - + CurrentEntry = MessageQueue->PostedMessagesListHead.Flink; ListHead = &MessageQueue->PostedMessagesListHead; @@ -1309,8 +1319,15 @@ MsqPeekMessage(IN PUSER_MESSAGE_QUEUE MessageQueue, if (IsListEmpty(CurrentEntry)) break; if (!CurrentMessage) break; CurrentEntry = CurrentEntry->Flink; - - if ( ( !Window || Window == HWND_BOTTOM || Window->head.h == CurrentMessage->Msg.hwnd ) && +/* + MSDN: + 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL. + 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL. + 3: handle to the window whose messages are to be retrieved. + */ + if ( ( !Window || // 1 + ( Window == HWND_BOTTOM && CurrentMessage->Msg.hwnd == NULL ) || // 2 + ( Window != HWND_BOTTOM && Window->head.h == CurrentMessage->Msg.hwnd ) ) && // 3 ( ( ( MsgFilterLow == 0 && MsgFilterHigh == 0 ) && CurrentMessage->QS_Flags & QSflags ) || ( MsgFilterLow <= CurrentMessage->Msg.message && MsgFilterHigh >= CurrentMessage->Msg.message ) ) ) { @@ -1337,13 +1354,12 @@ co_MsqWaitForNewMessages(PUSER_MESSAGE_QUEUE MessageQueue, PWND WndFilter, UINT MsgFilterMin, UINT MsgFilterMax) { NTSTATUS ret; - UserLeaveCo(); - ret = KeWaitForSingleObject(MessageQueue->NewMessages, - Executive, - UserMode, - FALSE, - NULL); + ret = KeWaitForSingleObject( MessageQueue->NewMessages, + UserRequest, + UserMode, + FALSE, + NULL ); UserEnterCo(); return ret; } @@ -1357,6 +1373,15 @@ MsqIsHung(PUSER_MESSAGE_QUEUE MessageQueue) return ((LargeTickCount.u.LowPart - MessageQueue->LastMsgRead) > MSQ_HUNG); } +VOID +CALLBACK +HungAppSysTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) +{ + //DoTheScreenSaver(); + DPRINT("HungAppSysTimerProc\n"); + // Process list of windows that are hung and waiting. +} + BOOLEAN FASTCALL MsqInitializeMessageQueue(struct _ETHREAD *Thread, PUSER_MESSAGE_QUEUE MessageQueue) { @@ -1405,7 +1430,7 @@ MsqCleanupMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue) PUSER_MESSAGE CurrentMessage; PUSER_SENT_MESSAGE CurrentSentMessage; PTHREADINFO pti; - + pti = MessageQueue->Thread->Tcb.Win32Thread; @@ -1428,7 +1453,7 @@ MsqCleanupMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue) DPRINT("Notify the sender and remove a message from the queue that had not been dispatched\n"); /* remove the message from the dispatching list if needed */ - if ((!(CurrentSentMessage->HookMessage & MSQ_SENTNOWAIT)) + if ((!(CurrentSentMessage->HookMessage & MSQ_SENTNOWAIT)) && (CurrentSentMessage->DispatchingListEntry.Flink != NULL)) { RemoveEntryList(&CurrentSentMessage->DispatchingListEntry); @@ -1555,6 +1580,8 @@ MsqDestroyMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue) { PDESKTOP desk; + MessageQueue->QF_flags |= QF_INDESTROY; + /* remove the message queue from any desktops */ if ((desk = InterlockedExchangePointer((PVOID*)&MessageQueue->Desktop, 0))) { diff --git a/subsystems/win32/win32k/ntuser/ntstubs.c b/subsystems/win32/win32k/ntuser/ntstubs.c index 7cdc720cd0a..06b84793c87 100644 --- a/subsystems/win32/win32k/ntuser/ntstubs.c +++ b/subsystems/win32/win32k/ntuser/ntstubs.c @@ -84,11 +84,11 @@ NtUserBitBltSysBmp( Ret = NtGdiBitBlt( hdc, nXDest, nYDest, - nWidth, - nHeight, + nWidth, + nHeight, hSystemBM, - nXSrc, - nYSrc, + nXSrc, + nYSrc, dwRop, 0, 0); @@ -255,7 +255,7 @@ HBRUSH APIENTRY NtUserGetControlColor( HWND hwndParent, - HWND hwnd, + HWND hwnd, HDC hdc, UINT CtlMsg) // Wine PaintRect: WM_CTLCOLORMSGBOX + hbrush { @@ -380,7 +380,7 @@ NtUserInitializeClientPfnArrays( DPRINT1("Failed reading Client Pfns from user space.\n"); SetLastNtError(Status); } - + UserLeave(); return Status; } @@ -539,37 +539,38 @@ NtUserSetSysColors( FLONG Flags) { DWORD Ret = TRUE; - NTSTATUS Status = STATUS_SUCCESS; if (cElements == 0) return TRUE; + /* We need this check to prevent overflow later */ + if ((ULONG)cElements >= 0x40000000) + { + EngSetLastError(ERROR_NOACCESS); + return FALSE; + } + UserEnterExclusive(); + _SEH2_TRY { - ProbeForRead(lpaElements, - sizeof(INT), - 1); - ProbeForRead(lpaRgbValues, - sizeof(COLORREF), - 1); -// Developers: We are thread locked and calling gdi. + ProbeForRead(lpaElements, cElements * sizeof(INT), 1); + ProbeForRead(lpaRgbValues, cElements * sizeof(COLORREF), 1); + IntSetSysColors(cElements, lpaElements, lpaRgbValues); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { - Status = _SEH2_GetExceptionCode(); - } - _SEH2_END; - if (!NT_SUCCESS(Status)) - { - SetLastNtError(Status); + SetLastNtError(_SEH2_GetExceptionCode()); Ret = FALSE; } + _SEH2_END; + if (Ret) { UserSendNotifyMessage(HWND_BROADCAST, WM_SYSCOLORCHANGE, 0, 0); } + UserLeave(); return Ret; } @@ -934,25 +935,25 @@ NtUserQueryInputContext( return 0; } -DWORD +BOOL APIENTRY NtUserRealInternalGetMessage( - DWORD dwUnknown1, - DWORD dwUnknown2, - DWORD dwUnknown3, - DWORD dwUnknown4, - DWORD dwUnknown5, - DWORD dwUnknown6) + LPMSG lpMsg, + HWND hWnd, + UINT wMsgFilterMin, + UINT wMsgFilterMax, + UINT wRemoveMsg, + BOOL bGMSG) { UNIMPLEMENTED; return 0; } -DWORD +BOOL APIENTRY NtUserRealWaitMessageEx( - DWORD dwUnknown1, - DWORD dwUnknown2) + DWORD dwWakeMask, + UINT uTimeout) { UNIMPLEMENTED; return 0; @@ -1251,10 +1252,10 @@ NtUserLockWindowUpdate(HWND hWnd) /* * @unimplemented */ -DWORD APIENTRY -NtUserRealChildWindowFromPoint(DWORD Unknown0, - DWORD Unknown1, - DWORD Unknown2) +HWND APIENTRY +NtUserRealChildWindowFromPoint(HWND Parent, + LONG x, + LONG y) { UNIMPLEMENTED diff --git a/subsystems/win32/win32k/ntuser/painting.c b/subsystems/win32/win32k/ntuser/painting.c index f2e3850437f..48919098be7 100644 --- a/subsystems/win32/win32k/ntuser/painting.c +++ b/subsystems/win32/win32k/ntuser/painting.c @@ -1248,6 +1248,7 @@ UserScrollDC( hrgnOwn = hrgnUpdate; if (!NtGdiSetRectRgn(hrgnOwn, rcDst.left, rcDst.top, rcDst.right, rcDst.bottom)) { + DC_UnlockDc(pDC); return ERROR; } } @@ -1265,8 +1266,8 @@ UserScrollDC( NtGdiOffsetRgn(hrgnTmp, dx, dy); Result = NtGdiCombineRgn(hrgnOwn, hrgnOwn, hrgnTmp, RGN_DIFF); - /* DO NOT Unlock DC while messing with prgnVis! */ - DC_UnlockDc(pDC); + /* DO NOT Unlock DC while messing with prgnVis! */ + DC_UnlockDc(pDC); REGION_FreeRgnByHandle(hrgnTmp); diff --git a/subsystems/win32/win32k/ntuser/simplecall.c b/subsystems/win32/win32k/ntuser/simplecall.c index d4a1a14f403..e5243d93ad1 100644 --- a/subsystems/win32/win32k/ntuser/simplecall.c +++ b/subsystems/win32/win32k/ntuser/simplecall.c @@ -119,6 +119,9 @@ NtUserCallNoParam(DWORD Routine) RETURN( (DWORD_PTR)MAKELONG(pti->ptLast.x, pti->ptLast.y)); } + case NOPARAM_ROUTINE_RELEASECAPTURE: + RETURN( (DWORD_PTR)IntReleaseCapture()); + default: DPRINT1("Calling invalid routine number 0x%x in NtUserCallNoParam\n", Routine); EngSetLastError(ERROR_INVALID_PARAMETER); @@ -252,7 +255,6 @@ NtUserCallOneParam( { BOOL ret = TRUE; - _SEH2_TRY { ProbeForWrite((POINT*)Param,sizeof(POINT),1); @@ -436,8 +438,7 @@ NtUserCallTwoParam( } case TWOPARAM_ROUTINE_ENABLEWINDOW: - UNIMPLEMENTED - RETURN( 0); + RETURN( IntEnableWindow((HWND)Param1, (BOOL)Param2)); case TWOPARAM_ROUTINE_SHOWOWNEDPOPUPS: { diff --git a/subsystems/win32/win32k/ntuser/window.c b/subsystems/win32/win32k/ntuser/window.c index 72d232b5393..f07a5455517 100644 --- a/subsystems/win32/win32k/ntuser/window.c +++ b/subsystems/win32/win32k/ntuser/window.c @@ -176,6 +176,50 @@ IntGetParent(PWND Wnd) return NULL; } +BOOL +FASTCALL +IntEnableWindow( HWND hWnd, BOOL bEnable ) +{ + BOOL Update; + PWND pWnd; + UINT bIsDisabled; + + if(!(pWnd = UserGetWindowObject(hWnd))) + { + return FALSE; + } + + /* check if updating is needed */ + bIsDisabled = (pWnd->style & WS_DISABLED); + Update = bIsDisabled; + + if (bEnable) + { + pWnd->style &= ~WS_DISABLED; + } + else + { + Update = !bIsDisabled; + + co_IntSendMessage( hWnd, WM_CANCELMODE, 0, 0); + + /* Remove keyboard focus from that window if it had focus */ + if (hWnd == IntGetThreadFocusWindow()) + { + co_UserSetFocus(NULL); + } + pWnd->style |= WS_DISABLED; + } + + if (Update) + { + IntNotifyWinEvent(EVENT_OBJECT_STATECHANGE, pWnd, OBJID_WINDOW, CHILDID_SELF, 0); + co_IntSendMessage(hWnd, WM_ENABLE, (LPARAM)bEnable, 0); + } + // Return nonzero if it was disabled, or zero if it wasn't: + return bIsDisabled; +} + /* * IntWinListChildren * @@ -1478,73 +1522,6 @@ NtUserBuildHwndList( return STATUS_SUCCESS; } - -/* - * @implemented - */ -HWND APIENTRY -NtUserChildWindowFromPointEx(HWND hwndParent, - LONG x, - LONG y, - UINT uiFlags) -{ - PWND Parent; - POINTL Pt; - HWND Ret; - HWND *List, *phWnd; - - if(!(Parent = UserGetWindowObject(hwndParent))) - { - return NULL; - } - - Pt.x = x; - Pt.y = y; - - if(Parent->head.h != IntGetDesktopWindow()) - { - Pt.x += Parent->rcClient.left; - Pt.y += Parent->rcClient.top; - } - - if(!IntPtInWindow(Parent, Pt.x, Pt.y)) - { - return NULL; - } - - Ret = Parent->head.h; - if((List = IntWinListChildren(Parent))) - { - for(phWnd = List; *phWnd; phWnd++) - { - PWND Child; - if((Child = UserGetWindowObject(*phWnd))) - { - if(!(Child->style & WS_VISIBLE) && (uiFlags & CWP_SKIPINVISIBLE)) - { - continue; - } - if((Child->style & WS_DISABLED) && (uiFlags & CWP_SKIPDISABLED)) - { - continue; - } - if((Child->ExStyle & WS_EX_TRANSPARENT) && (uiFlags & CWP_SKIPTRANSPARENT)) - { - continue; - } - if(IntPtInWindow(Child, Pt.x, Pt.y)) - { - Ret = Child->head.h; - break; - } - } - } - ExFreePool(List); - } - - return Ret; -} - static void IntSendParentNotify( PWND pWindow, UINT msg ) { if ( (pWindow->style & (WS_CHILD | WS_POPUP)) == WS_CHILD && @@ -1552,10 +1529,14 @@ static void IntSendParentNotify( PWND pWindow, UINT msg ) { if (pWindow->spwndParent && pWindow->spwndParent != UserGetDesktopWindow()) { - co_IntSendMessage( pWindow->spwndParent->head.h, - WM_PARENTNOTIFY, - MAKEWPARAM( msg, pWindow->IDMenu), - (LPARAM)pWindow->head.h ); + USER_REFERENCE_ENTRY Ref; + UserRefObjectCo(pWindow->spwndParent, &Ref); + // Should be co_IntSendMessage please retest, Ref to Chg, revision 51254... + co_IntSendMessageNoWait( pWindow->spwndParent->head.h, + WM_PARENTNOTIFY, + MAKEWPARAM( msg, pWindow->IDMenu), + (LPARAM)pWindow->head.h ); + UserDerefObjectCo(pWindow->spwndParent); } } } diff --git a/subsystems/win32/win32k/ntuser/winpos.c b/subsystems/win32/win32k/ntuser/winpos.c index 3934dcb21b6..7b9a6f6fa44 100644 --- a/subsystems/win32/win32k/ntuser/winpos.c +++ b/subsystems/win32/win32k/ntuser/winpos.c @@ -1797,6 +1797,72 @@ BOOL FASTCALL IntEndDeferWindowPosEx( HDWP hdwp ) return res; } +/* + * @implemented + */ +HWND APIENTRY +NtUserChildWindowFromPointEx(HWND hwndParent, + LONG x, + LONG y, + UINT uiFlags) +{ + PWND Parent; + POINTL Pt; + HWND Ret; + HWND *List, *phWnd; + + if(!(Parent = UserGetWindowObject(hwndParent))) + { + return NULL; + } + + Pt.x = x; + Pt.y = y; + + if(Parent->head.h != IntGetDesktopWindow()) + { + Pt.x += Parent->rcClient.left; + Pt.y += Parent->rcClient.top; + } + + if(!IntPtInWindow(Parent, Pt.x, Pt.y)) + { + return NULL; + } + + Ret = Parent->head.h; + if((List = IntWinListChildren(Parent))) + { + for(phWnd = List; *phWnd; phWnd++) + { + PWND Child; + if((Child = UserGetWindowObject(*phWnd))) + { + if(!(Child->style & WS_VISIBLE) && (uiFlags & CWP_SKIPINVISIBLE)) + { + continue; + } + if((Child->style & WS_DISABLED) && (uiFlags & CWP_SKIPDISABLED)) + { + continue; + } + if((Child->ExStyle & WS_EX_TRANSPARENT) && (uiFlags & CWP_SKIPTRANSPARENT)) + { + continue; + } + if(IntPtInWindow(Child, Pt.x, Pt.y)) + { + Ret = Child->head.h; + break; + } + } + } + ExFreePool(List); + } + + return Ret; +} + /* * @implemented */ diff --git a/subsystems/win32/win32k/objects/brush.c b/subsystems/win32/win32k/objects/brush.c index 5ad5f0764bf..72b7fd3864a 100644 --- a/subsystems/win32/win32k/objects/brush.c +++ b/subsystems/win32/win32k/objects/brush.c @@ -162,6 +162,54 @@ FreeObjectAttr(PVOID pAttr) return; } +BOOL +FASTCALL +IntGdiSetBrushOwner(PBRUSH pbr, DWORD OwnerMask) +{ + HBRUSH hBR; + PEPROCESS Owner = NULL; + PGDI_TABLE_ENTRY pEntry = NULL; + + if (!pbr) return FALSE; + + hBR = pbr->BaseObject.hHmgr; + + if (!hBR || (GDI_HANDLE_GET_TYPE(hBR) != GDI_OBJECT_TYPE_BRUSH)) + return FALSE; + else + { + INT Index = GDI_HANDLE_GET_INDEX((HGDIOBJ)hBR); + pEntry = &GdiHandleTable->Entries[Index]; + } + + if (pbr->flAttrs & GDIBRUSH_IS_GLOBAL) + { + GDIOBJ_ShareUnlockObjByPtr((POBJ)pbr); + return TRUE; + } + + if ((OwnerMask == GDI_OBJ_HMGR_PUBLIC) || OwnerMask == GDI_OBJ_HMGR_NONE) + { + // Set this Brush to inaccessible mode and to an Owner of NONE. +// if (OwnerMask == GDI_OBJ_HMGR_NONE) Owner = OwnerMask; + + if (!GDIOBJ_SetOwnership((HGDIOBJ) hBR, Owner)) + return FALSE; + + // Deny user access to User Data. + pEntry->UserData = NULL; // This hBR is inaccessible! + } + + if (OwnerMask == GDI_OBJ_HMGR_POWNED) + { + if (!GDIOBJ_SetOwnership((HGDIOBJ) hBR, PsGetCurrentProcess() )) + return FALSE; + + // Allow user access to User Data. + pEntry->UserData = pbr->pBrushAttr; + } + return TRUE; +} BOOL INTERNAL_CALL diff --git a/subsystems/win32/win32k/objects/dclife.c b/subsystems/win32/win32k/objects/dclife.c index 7d6d330e708..b83c6f039fd 100644 --- a/subsystems/win32/win32k/objects/dclife.c +++ b/subsystems/win32/win32k/objects/dclife.c @@ -836,7 +836,7 @@ IntGdiDeleteDC(HDC hDC, BOOL Force) { DPRINT1("Attempted to Delete 0x%x currently being destroyed!!!\n", hDC); } - + return TRUE; } @@ -973,3 +973,45 @@ IntGdiCreateDisplayDC(HDEV hDev, ULONG DcType, BOOL EmptyDC) return hDC; } +BOOL +FASTCALL +IntGdiSetDCOwnerEx( HDC hDC, DWORD OwnerMask, BOOL NoSetBrush) +{ + PDC pDC; + BOOL Ret = FALSE; + + if (!hDC || (GDI_HANDLE_GET_TYPE(hDC) != GDI_OBJECT_TYPE_DC)) return FALSE; + + if ((OwnerMask == GDI_OBJ_HMGR_PUBLIC) || OwnerMask == GDI_OBJ_HMGR_NONE) + { + pDC = DC_LockDc ( hDC ); + MmCopyFromCaller(&pDC->dcattr, pDC->pdcattr, sizeof(DC_ATTR)); + DC_vFreeDcAttr(pDC); + DC_UnlockDc( pDC ); + + if (!DC_SetOwnership( hDC, NULL )) // This hDC is inaccessible! + return Ret; + } + + if (OwnerMask == GDI_OBJ_HMGR_POWNED) + { + pDC = DC_LockDc ( hDC ); + ASSERT(pDC->pdcattr == &pDC->dcattr); + DC_UnlockDc( pDC ); + + if (!DC_SetOwnership( hDC, PsGetCurrentProcess() )) return Ret; + + DC_AllocateDcAttr( hDC ); // Allocate new dcattr + + DCU_SynchDcAttrtoUser( hDC ); // Copy data from dc to dcattr + } + + if ((OwnerMask != GDI_OBJ_HMGR_NONE) && !NoSetBrush) + { + pDC = DC_LockDc ( hDC ); + if (IntGdiSetBrushOwner((PBRUSH)pDC->dclevel.pbrFill, OwnerMask)) + IntGdiSetBrushOwner((PBRUSH)pDC->dclevel.pbrLine, OwnerMask); + DC_UnlockDc( pDC ); + } + return TRUE; +} diff --git a/subsystems/win32/win32k/objects/gdiobj.c b/subsystems/win32/win32k/objects/gdiobj.c index 6bbca8cddd4..6c6be35895c 100644 --- a/subsystems/win32/win32k/objects/gdiobj.c +++ b/subsystems/win32/win32k/objects/gdiobj.c @@ -70,7 +70,7 @@ OBJ_TYPE_INFO ObjTypeInfo[BASE_OBJTYPE_COUNT] = static LARGE_INTEGER ShortDelay; PGDI_HANDLE_TABLE GdiHandleTable = NULL; -PSECTION_OBJECT GdiTableSection = NULL; +static PSECTION_OBJECT GdiTableSection = NULL; /** INTERNAL FUNCTIONS ********************************************************/ @@ -741,16 +741,22 @@ IsObjectDead(HGDIOBJ hObject) } } - +/* + * Process Environment Cached GDI Handles + * + * What types of GDI handle objects that are cached in the GDI handle buffer? + * Brushes set to BS_SOLID, Pens with widths of zero or set to PS_SOLID, and + * Regions that are set to NULLREGION or SIMPLEREGION. + */ BOOL FASTCALL bPEBCacheHandle(HGDIOBJ Handle, int oType, PVOID pAttr) { PGDIHANDLECACHE GdiHandleCache; HGDIOBJ *hPtr; - BOOL Ret = FALSE; - int Offset = 0, Number; HANDLE Lock; + int Number, Offset, MaxNum = CACHE_PEN_ENTRIES; + BOOL Ret = FALSE; GdiHandleCache = (PGDIHANDLECACHE)NtCurrentTeb()->ProcessEnvironmentBlock->GdiHandleBuffer; @@ -758,6 +764,7 @@ bPEBCacheHandle(HGDIOBJ Handle, int oType, PVOID pAttr) { case hctBrushHandle: Offset = 0; + MaxNum = CACHE_BRUSH_ENTRIES; break; case hctPenHandle: @@ -783,10 +790,10 @@ bPEBCacheHandle(HGDIOBJ Handle, int oType, PVOID pAttr) hPtr = GdiHandleCache->Handle + Offset; - if ( pAttr && oType == hctRegionHandle) + if ( pAttr ) { - if ( Number < CACHE_REGION_ENTRIES ) - { + if ( Number < MaxNum ) + { // This object is cached and waiting for it's resurrection by the users. ((PRGN_ATTR)pAttr)->AttrFlags |= ATTR_CACHED; hPtr[Number] = Handle; GdiHandleCache->ulNumHandles[oType]++; @@ -817,6 +824,7 @@ GreDeleteObject(HGDIOBJ hObject) INT Index; PGDI_TABLE_ENTRY Entry; DWORD dwObjectType; + INT ihct; PVOID pAttr = NULL; DPRINT("NtGdiDeleteObject handle 0x%08x\n", hObject); @@ -831,14 +839,27 @@ GreDeleteObject(HGDIOBJ hObject) switch (dwObjectType) { case GDI_OBJECT_TYPE_BRUSH: + ihct = hctBrushHandle; + break; + + case GDI_OBJECT_TYPE_PEN: + ihct = hctPenHandle; break; case GDI_OBJECT_TYPE_REGION: - /* If pAttr NULL, the probability is high for System Region. */ + ihct = hctRegionHandle; + break; + } + + switch (dwObjectType) + { +// case GDI_OBJECT_TYPE_BRUSH: +// case GDI_OBJECT_TYPE_PEN: + case GDI_OBJECT_TYPE_REGION: + /* If pAttr NULL, the probability is high for System GDI handle object. */ if ( pAttr && - bPEBCacheHandle(hObject, hctRegionHandle, pAttr)) - { - /* User space handle only! */ + bPEBCacheHandle(hObject, ihct, pAttr) ) + { /* User space handle only! */ return TRUE; } if (pAttr) @@ -847,10 +868,6 @@ GreDeleteObject(HGDIOBJ hObject) Entry->UserData = NULL; } break; - - case GDI_OBJECT_TYPE_DC: -// DC_FreeDcAttr(hObject); - break; } return NULL != hObject @@ -1646,7 +1663,7 @@ LockHandleFrom: } PVOID INTERNAL_CALL -GDI_MapHandleTable(PSECTION_OBJECT SectionObject, PEPROCESS Process) +GDI_MapHandleTable(PEPROCESS Process) { PVOID MappedView = NULL; NTSTATUS Status; @@ -1655,10 +1672,10 @@ GDI_MapHandleTable(PSECTION_OBJECT SectionObject, PEPROCESS Process) Offset.QuadPart = 0; - ASSERT(SectionObject != NULL); + ASSERT(GdiTableSection != NULL); ASSERT(Process != NULL); - Status = MmMapViewOfSection(SectionObject, + Status = MmMapViewOfSection(GdiTableSection, Process, &MappedView, 0, @@ -1709,126 +1726,6 @@ GDIOBJ_LockMultipleObjs(ULONG ulCount, /** PUBLIC FUNCTIONS **********************************************************/ -BOOL -FASTCALL -IntGdiSetRegionOwner(HRGN hRgn, DWORD OwnerMask) -{ - INT Index; - PGDI_TABLE_ENTRY Entry; -/* - System Regions: - These regions do not use attribute sections and when allocated, use gdiobj - level functions. - */ - // FIXME! HAX!!! Remove this once we get everything right! - Index = GDI_HANDLE_GET_INDEX(hRgn); - Entry = &GdiHandleTable->Entries[Index]; - if (Entry->UserData) FreeObjectAttr(Entry->UserData); - Entry->UserData = NULL; - // - if ((OwnerMask == GDI_OBJ_HMGR_PUBLIC) || OwnerMask == GDI_OBJ_HMGR_NONE) - { - return GDIOBJ_SetOwnership(hRgn, NULL); - } - if (OwnerMask == GDI_OBJ_HMGR_POWNED) - { - return GDIOBJ_SetOwnership((HGDIOBJ) hRgn, PsGetCurrentProcess() ); - } - return FALSE; -} - -BOOL -FASTCALL -IntGdiSetBrushOwner(PBRUSH pbr, DWORD OwnerMask) -{ - HBRUSH hBR; - PEPROCESS Owner = NULL; - PGDI_TABLE_ENTRY pEntry = NULL; - - if (!pbr) return FALSE; - - hBR = pbr->BaseObject.hHmgr; - - if (!hBR || (GDI_HANDLE_GET_TYPE(hBR) != GDI_OBJECT_TYPE_BRUSH)) - return FALSE; - else - { - INT Index = GDI_HANDLE_GET_INDEX((HGDIOBJ)hBR); - pEntry = &GdiHandleTable->Entries[Index]; - } - - if (pbr->flAttrs & GDIBRUSH_IS_GLOBAL) - { - GDIOBJ_ShareUnlockObjByPtr((POBJ)pbr); - return TRUE; - } - - if ((OwnerMask == GDI_OBJ_HMGR_PUBLIC) || OwnerMask == GDI_OBJ_HMGR_NONE) - { - // Set this Brush to inaccessible mode and to an Owner of NONE. -// if (OwnerMask == GDI_OBJ_HMGR_NONE) Owner = OwnerMask; - - if (!GDIOBJ_SetOwnership((HGDIOBJ) hBR, Owner)) - return FALSE; - - // Deny user access to User Data. - pEntry->UserData = NULL; // This hBR is inaccessible! - } - - if (OwnerMask == GDI_OBJ_HMGR_POWNED) - { - if (!GDIOBJ_SetOwnership((HGDIOBJ) hBR, PsGetCurrentProcess() )) - return FALSE; - - // Allow user access to User Data. - pEntry->UserData = pbr->pBrushAttr; - } - return TRUE; -} - -BOOL -FASTCALL -IntGdiSetDCOwnerEx( HDC hDC, DWORD OwnerMask, BOOL NoSetBrush) -{ - PDC pDC; - BOOL Ret = FALSE; - - if (!hDC || (GDI_HANDLE_GET_TYPE(hDC) != GDI_OBJECT_TYPE_DC)) return FALSE; - - if ((OwnerMask == GDI_OBJ_HMGR_PUBLIC) || OwnerMask == GDI_OBJ_HMGR_NONE) - { - pDC = DC_LockDc ( hDC ); - MmCopyFromCaller(&pDC->dcattr, pDC->pdcattr, sizeof(DC_ATTR)); - DC_vFreeDcAttr(pDC); - DC_UnlockDc( pDC ); - - if (!DC_SetOwnership( hDC, NULL )) // This hDC is inaccessible! - return Ret; - } - - if (OwnerMask == GDI_OBJ_HMGR_POWNED) - { - pDC = DC_LockDc ( hDC ); - ASSERT(pDC->pdcattr == &pDC->dcattr); - DC_UnlockDc( pDC ); - - if (!DC_SetOwnership( hDC, PsGetCurrentProcess() )) return Ret; - - DC_AllocateDcAttr( hDC ); // Allocate new dcattr - - DCU_SynchDcAttrtoUser( hDC ); // Copy data from dc to dcattr - } - - if ((OwnerMask != GDI_OBJ_HMGR_NONE) && !NoSetBrush) - { - pDC = DC_LockDc ( hDC ); - if (IntGdiSetBrushOwner((PBRUSH)pDC->dclevel.pbrFill, OwnerMask)) - IntGdiSetBrushOwner((PBRUSH)pDC->dclevel.pbrLine, OwnerMask); - DC_UnlockDc( pDC ); - } - return TRUE; -} - INT FASTCALL GreGetObjectOwner(HGDIOBJ Handle, GDIOBJTYPE ObjType) diff --git a/subsystems/win32/win32k/objects/region.c b/subsystems/win32/win32k/objects/region.c index d0bd3bafc61..9a267493002 100644 --- a/subsystems/win32/win32k/objects/region.c +++ b/subsystems/win32/win32k/objects/region.c @@ -2080,6 +2080,7 @@ REGION_AllocUserRgnWithHandle(INT nRgn) { Entry = GDI_HANDLE_GET_ENTRY(GdiHandleTable, pRgn->BaseObject.hHmgr); Entry->UserData = AllocateObjectAttr(); + RtlZeroMemory(Entry->UserData, sizeof(RGN_ATTR)); } return pRgn; } @@ -2090,6 +2091,7 @@ RGNOBJAPI_Lock(HRGN hRgn, PRGN_ATTR *ppRgn_Attr) { PGDI_TABLE_ENTRY Entry; PRGN_ATTR pRgn_Attr; + BOOL Hit = FALSE; PROSRGNDATA pRgn = NULL; pRgn = REGION_LockRgn(hRgn); @@ -2103,11 +2105,12 @@ RGNOBJAPI_Lock(HRGN hRgn, PRGN_ATTR *ppRgn_Attr) { _SEH2_TRY { - if ( !(pRgn_Attr->AttrFlags & ATTR_CACHED) && - pRgn_Attr->AttrFlags & (ATTR_RGN_VALID|ATTR_RGN_DIRTY) ) + if ( !(pRgn_Attr->AttrFlags & ATTR_CACHED) ) { - switch (pRgn_Attr->Flags) + if ( pRgn_Attr->AttrFlags & (ATTR_RGN_VALID|ATTR_RGN_DIRTY) ) { + switch (pRgn_Attr->Flags) + { case NULLREGION: EMPTY_REGION( pRgn ); break; @@ -2119,8 +2122,13 @@ RGNOBJAPI_Lock(HRGN hRgn, PRGN_ATTR *ppRgn_Attr) pRgn_Attr->Rect.right, pRgn_Attr->Rect.bottom ); break; + } + pRgn_Attr->AttrFlags &= ~ATTR_RGN_DIRTY; } - pRgn_Attr->AttrFlags &= ~ATTR_RGN_DIRTY; + } + else + { // This object is cached an waiting for it's resurrection by the users. + Hit = TRUE; } } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) @@ -2128,6 +2136,11 @@ RGNOBJAPI_Lock(HRGN hRgn, PRGN_ATTR *ppRgn_Attr) } _SEH2_END; + if (Hit) + { + REGION_UnlockRgn(pRgn); + return NULL; + } if (ppRgn_Attr) *ppRgn_Attr = pRgn_Attr; } @@ -2281,6 +2294,34 @@ IntUpdateVisRectRgn(PDC pDC, PROSRGNDATA pRgn) } } +BOOL +FASTCALL +IntGdiSetRegionOwner(HRGN hRgn, DWORD OwnerMask) +{ + INT Index; + PGDI_TABLE_ENTRY Entry; +/* + System Regions: + These regions do not use attribute sections and when allocated, use gdiobj + level functions. + */ + // FIXME! HAX!!! Remove this once we get everything right! + Index = GDI_HANDLE_GET_INDEX(hRgn); + Entry = &GdiHandleTable->Entries[Index]; + if (Entry->UserData) FreeObjectAttr(Entry->UserData); + Entry->UserData = NULL; + // + if ((OwnerMask == GDI_OBJ_HMGR_PUBLIC) || OwnerMask == GDI_OBJ_HMGR_NONE) + { + return GDIOBJ_SetOwnership(hRgn, NULL); + } + if (OwnerMask == GDI_OBJ_HMGR_POWNED) + { + return GDIOBJ_SetOwnership((HGDIOBJ) hRgn, PsGetCurrentProcess() ); + } + return FALSE; +} + INT FASTCALL IntGdiCombineRgn(PROSRGNDATA destRgn,