From 49b663a0a1d0f4f01ff76aecbd0387fc427a2e65 Mon Sep 17 00:00:00 2001 From: Marc Piulachs Date: Mon, 22 Oct 2007 19:55:26 +0000 Subject: [PATCH] Wine imported xcopy command line tool svn path=/trunk/; revision=29794 --- .../applications/cmdutils/cmdutils.rbuild | 3 + .../base/applications/cmdutils/xcopy/En.rc | 79 ++ .../base/applications/cmdutils/xcopy/Ko.rc | 80 ++ .../base/applications/cmdutils/xcopy/Pl.rc | 79 ++ .../base/applications/cmdutils/xcopy/Ru.rc | 82 ++ .../base/applications/cmdutils/xcopy/rsrc.rc | 28 + .../base/applications/cmdutils/xcopy/xcopy.c | 1041 +++++++++++++++++ .../base/applications/cmdutils/xcopy/xcopy.h | 68 ++ .../applications/cmdutils/xcopy/xcopy.rbuild | 11 + .../base/applications/cmdutils/xcopy/xcopy.rc | 17 + 10 files changed, 1488 insertions(+) create mode 100644 reactos/base/applications/cmdutils/xcopy/En.rc create mode 100644 reactos/base/applications/cmdutils/xcopy/Ko.rc create mode 100644 reactos/base/applications/cmdutils/xcopy/Pl.rc create mode 100644 reactos/base/applications/cmdutils/xcopy/Ru.rc create mode 100644 reactos/base/applications/cmdutils/xcopy/rsrc.rc create mode 100644 reactos/base/applications/cmdutils/xcopy/xcopy.c create mode 100644 reactos/base/applications/cmdutils/xcopy/xcopy.h create mode 100644 reactos/base/applications/cmdutils/xcopy/xcopy.rbuild create mode 100644 reactos/base/applications/cmdutils/xcopy/xcopy.rc diff --git a/reactos/base/applications/cmdutils/cmdutils.rbuild b/reactos/base/applications/cmdutils/cmdutils.rbuild index 8eaafc5e2ab..9a53d970553 100644 --- a/reactos/base/applications/cmdutils/cmdutils.rbuild +++ b/reactos/base/applications/cmdutils/cmdutils.rbuild @@ -10,4 +10,7 @@ + + + diff --git a/reactos/base/applications/cmdutils/xcopy/En.rc b/reactos/base/applications/cmdutils/xcopy/En.rc new file mode 100644 index 00000000000..d7d4344e06a --- /dev/null +++ b/reactos/base/applications/cmdutils/xcopy/En.rc @@ -0,0 +1,79 @@ +/* + * XCOPY - Wine-compatible xcopy program + * English language support + * + * Copyright (C) 2007 J. Edmeades + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + + +LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT + +STRINGTABLE +{ + STRING_INVPARMS, "Invalid number of parameters - Use xcopy /? for help\n" + STRING_INVPARM, "Invalid parameter '%s' - Use xcopy /? for help\n" + STRING_PAUSE, "Press to begin copying\n" + STRING_SIMCOPY, "%d file(s) would be copied\n" + STRING_COPY, "%d file(s) copied\n" + STRING_QISDIR, "Is '%s' a filename or directory\n" \ + "on the target?\n" \ + "(F - File, D - Directory)\n" + STRING_SRCPROMPT,"%s? (Yes|No)\n" + STRING_OVERWRITE,"Overwrite %s? (Yes|No|All)\n" + STRING_COPYFAIL, "Copying of '%s' to '%s' failed with r/c %d\n" + STRING_OPENFAIL, "Failed to open '%s'\n" + STRING_READFAIL, "Failed during reading of '%s'\n" + STRING_YES_CHAR, "Y" + STRING_NO_CHAR, "N" + STRING_ALL_CHAR, "A" + STRING_FILE_CHAR,"F" + STRING_DIR_CHAR, "D" + + STRING_HELP, +"XCOPY - Copies source files or directory trees to a destination\n\ +\n\ +Syntax:\n\ +XCOPY source [dest] [/I] [/S] [/Q] [/F] [/L] [/W] [/T] [/N] [/U] \n\ +\t [/R] [/H] [/C] [/P] [/A] [/M] [/E] [/D] [/Y] [/-Y]\n\ +\n\ +Where:\n\ +\n\ +[/I] Assume directory if destination does not exist and copying 2 or \n\ +\tmore files\n\ +[/S] Copy directories and subdirectories\n\ +[/E] Copy directories and subdirectories, including any empty ones\n\ +[/Q] Do not list names during copy, ie quiet.\n\ +[/F] Show full source and destination names during copy\n\ +[/L] Simulate operation, showing names which would be copied\n\ +[/W] Prompts before beginning the copy operation\n\ +[/T] Creates empty directory structure but does not copy files\n\ +[/Y] Suppress prompting when overwriting files\n\ +[/-Y] Enable prompting when overwriting files\n\ +[/P] Prompts on each source file before copying\n\ +[/N] Copy using short names\n\ +[/U] Copy only files which already exist in destination\n\ +[/R] Overwrite any read only files\n\ +[/H] Include hidden and system files in the copy\n\ +[/C] Continue even if an error occurs during the copy\n\ +[/A] Only copy files with archive attribute set\n\ +[/M] Only copy files with archive attribute set, removes \n\ +\tarchive attribute\n\ +[/D | /D:m-d-y] Copy new files or those modified after the supplied date.\n\ +\t\tIf no date is supplied, only copy if destination is older\n\ +\t\tthan source\n\n" + +} diff --git a/reactos/base/applications/cmdutils/xcopy/Ko.rc b/reactos/base/applications/cmdutils/xcopy/Ko.rc new file mode 100644 index 00000000000..843be888fa6 --- /dev/null +++ b/reactos/base/applications/cmdutils/xcopy/Ko.rc @@ -0,0 +1,80 @@ +/* + * XCOPY - Wine-compatible xcopy program + * Korean language support + * + * Copyright (C) 2007 J. Edmeades + * Copyright (C) 2007 YunSong Hwang(hys545@dreamwiz.com) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + + +LANGUAGE LANG_KOREAN, SUBLANG_DEFAULT + +STRINGTABLE +{ + STRING_INVPARMS, "¿Ã¹Ù¸£Áö ¾ÊÀº ¸Å°³º¯¼öÀÇ °¹¼ö - xcopy /?·Î µµ¿ò¸»À» º¸½Ã¿À\n" + STRING_INVPARM, "¿Ã¹Ù¸£Áö ¾ÊÀº ¸Å°³º¯¼ö '%s' - xcopy /?·Î µµ¿ò¸»À» º¸½Ã¿À\n" + STRING_PAUSE, " ¸¦ ´©¸£¸é º¹»ç°¡ ½ÃÀÛµÉ °ÍÀÔ´Ï´Ù\n" + STRING_SIMCOPY, "%d ÆÄÀÏÀÌ º¹»çµÉ °ÍÀÔ´Ï´Ù\n" + STRING_COPY, "%d ÆÄÀÏÀÌ º¹»çµÇ¾ú½À´Ï´Ù\n" + STRING_QISDIR, "'%s'ÀÌ º¹»çÇÒ ÆÄÀÏÀ̳ª µð·ºÅ丮?\n" \ + "ÀԴϱî?\n" \ + "(F - ÆÄÀÏ, D - µð·ºÅ丮)\n" + STRING_SRCPROMPT,"%s? (¿¹|¾Æ´Ï¿À)\n" + STRING_OVERWRITE,"%s¸¦ µ¤¾î¾²°Ú½À´Ï±î? (¿¹|¾Æ´Ï¿À|¸ðµÎ)\n" + STRING_COPYFAIL, "Copying of '%s' to '%s' failed with r/c %d\n" + STRING_OPENFAIL, "'%s' ¿­±â ½ÇÆÐ\n" + STRING_READFAIL, "'%s¸¦ ÀÐÁö ¸øÇß½À´Ï´Ù'\n" + STRING_YES_CHAR, "Y" + STRING_NO_CHAR, "N" + STRING_ALL_CHAR, "A" + STRING_FILE_CHAR,"F" + STRING_DIR_CHAR, "D" + + STRING_HELP, +"XCOPY - ¿øº» ÆÄÀÏÀ̳ª µð·ºÅ丮 ±¸Á¶¸¦ ¸ñÀûÁö·Î º¹»ç\n\ +\n\ +¹®¹ý:\n\ +XCOPY ¿øº» [´ë»ó] [/I] [/S] [/Q] [/F] [/L] [/W] [/T] [/N] [/U] \n\ +\t [/R] [/H] [/C] [/P] [/A] [/M] [/E] [/D] [/Y] [/-Y]\n\ +\n\ +Where:\n\ +\n\ +[/I] Assume directory if destination does not exist and copying 2 or \n\ +\tmore files\n\ +[/S] µð·ºÅ丮ÇÏ°í ÇÏÀ§ µð·ºÅ丮 º¹»ç\n\ +[/E] ºó µð·ºÅ丮¸¦ Æ÷ÇÔÇؼ­ µð·ºÅ丮¿Í ÇÏÀ§ µð·ºÅ丮 º¹»ç\n\ +[/Q] Á¶¿ëÇÏ°Ô º¹»çµÇ´Â ÆÄÀÏÀ̳ª µð·ºÅ丮¸¦ Ç¥½ÃÇÏÁö ¾Ê°í º¹»ç.\n\ +[/F] º¹»çÇÏ´Â µ¿¾È ¿ÏÀüÇÑ ¿øº»°ú ´ë»ó º¸¿©ÁÖ±â\n\ +[/L] º¹»çµÉ °ÍÀ» º¸¿©Áָ鼭 °¡»óÀ¸·Î ÀÛ¾÷\n\ +[/W] º¹»ç½ÃÀÛ Çϱâ Àü¿¡ È®ÀÎÇϱâ\n\ +[/T] ÆÄÀÏÀº º¹»çÇÏÁö ¾Ê°í ºó µð·ºÅ丮 ±¸Á¶¸¸ º¹»ç\n\ +[/Y] ÆÄÀÏ µ¤¾î ¾µ ¶§ È®ÀÎÇÏÁö ¾Ê±â\n\ +[/-Y] ÆÄÀÏÀ» µ¤¾î ¾µ ¶§ È®ÀÎÇϱâ\n\ +[/P] º¹»çÇÏ´Â µ¿¾È¿¡ °¢°¡ÀÇ ¿øº» ÆÄÀϸ¶´Ù È®ÀÎ\n\ +[/N] ªÀº À̸§À» »ç¿ëÇؼ­ º¹»ç\n\ +[/U] ÀÌ¹Ì ´ë»ó µð·ºÅ丮¿¡ Á¸ÀçÇÏ´Â ÆÄÀϸ¸ º¹»ç\n\ +[/R] Àбâ Àü¿ë ÆÄÀϵµ µ¤¾î ¾²±â\n\ +[/H] ¼ûÀº ÆÄÀÏÀ̳ª ½Ã½ºÅÛ ÆÄÀϵµ Æ÷ÇÔÇؼ­ º¹»ç\n\ +[/C] º¹»çÇÏ´Â µ¿¾È¿¡ ¿¡·¯°¡ ¹ß»ýÇصµ °è¼Ó ÁøÇà\n\ +[/A] ¿ÀÁ÷ ¾ÐÃà ¼Ó¼ºÀÌ ¼³Á¤µÇ¾îÀÖ´Â ÆÄÀϸ¸ º¹»ç\n\ +[/M] ¿ÀÁ÷ ¾ÐÃà ¼Ó¼ºÀ» Á¦°ÅÇϸ鼭 ¾ÐÃà ¼Ó¼ºÀÌ ¼³Á¤µÇ¾îÀÖ´Â \n\ +\ÆÄÀϸ¸ º¹»ç \n\ +[/D | /D:m-d-y] Copy new files or those modified after the supplied date.\n\ +\t\tIf no date is supplied, only copy if destination is older\n\ +\t\tthan source\n\n" + +} diff --git a/reactos/base/applications/cmdutils/xcopy/Pl.rc b/reactos/base/applications/cmdutils/xcopy/Pl.rc new file mode 100644 index 00000000000..10176aadc8e --- /dev/null +++ b/reactos/base/applications/cmdutils/xcopy/Pl.rc @@ -0,0 +1,79 @@ +/* + * XCOPY - Wine-compatible xcopy program + * Polish language support + * + * Copyright (C) 2007 J. Edmeades + * Copyright (C) 2007 Mikolaj Zalewski + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + + +LANGUAGE LANG_POLISH, SUBLANG_DEFAULT + +STRINGTABLE +{ + STRING_INVPARMS, "Niew³aœciwa liczba parametrów - uruchom xcopy /? aby wyœwietliæ pomoc\n" + STRING_INVPARM, "Nieznany parameter '%s' - uruchom xcopy /? aby wyœwietliæ pomoc\n" + STRING_PAUSE, "Naciœnij aby rozpocz¹æ kopiowanie\n" + STRING_SIMCOPY, "%d plik(ów) zosta³oby skopiowanych\n" + STRING_COPY, "%d plik(ów) skopiowanych\n" + STRING_QISDIR, "Czy '%s' jest nazw¹ pliku czy katalogu\n" \ + "docelowego?\n" \ + "(P - plik, K - katalog)\n" + STRING_SRCPROMPT,"%s? (Tak|Nie)\n" + STRING_OVERWRITE,"Zast¹piæ %s? (Tak|Nie|Wszystkie)\n" + STRING_COPYFAIL, "Kopiowanie '%s' do '%s' nie powiod³o siê - kod b³êdu %d\n" + STRING_OPENFAIL, "Nie uda³o siê otworzyæ '%s'\n" + STRING_READFAIL, "B³¹d podczas czytania '%s'\n" + STRING_YES_CHAR, "T" + STRING_NO_CHAR, "N" + STRING_ALL_CHAR, "W" + STRING_FILE_CHAR,"P" + STRING_DIR_CHAR, "K" + + STRING_HELP, +"XCOPY - kopiuje pliki lub drzewa katalogów\n\ +\n\ +Sk³adnia:\n\ +XCOPY Ÿród³o [cel] [/I] [/S] [/Q] [/F] [/L] [/W] [/T] [/N] [/U] \n\ +\t [/R] [/H] [/C] [/P] [/A] [/M] [/E] [/D] [/Y] [/-Y]\n\ +\n\ +Gdzie:\n\ +\n\ +[/I] Je¿eli \"cel\" nie istnieje i kopiowane s¹ co najmniej dwa pliki,\n\ +\tzak³ada, ¿e \"cel\" powien byæ katalogiem\n\ +[/S] Kopiuje katalogi i podkatalogi\n\ +[/E] Kopiuje katalogi i podkatalogi, ³¹cznie z pustymi\n\ +[/Q] Nie wypisuje nazw plików podczas kopiowania (tryb cichy)\n\ +[/F] Wypisuje pe³ne œcie¿ki Ÿród³owe i docelowe podczas kopiowania\n\ +[/L] Jedynie symuluje operacjê, pokazuj¹c pliki, które by³yby kopiowane\n\ +[/W] Prosi o potwierdzenie przed rozpoczêciem kopiowania\n\ +[/T] Tworzy puste katalogi, ale nie kopiuje plików\n\ +[/Y] Zastêpuje pliki bez proœby o potwierdzenie\n\ +[/-Y] Zawsze prosi o potwierdzenie przed zast¹pieniem pliku\n\ +[/P] Prosi o potwierdzenie przed skopiowaniem ka¿dego pliku\n\ +[/N] Kopiuje u¿ywaj¹c krótkich nazw plików\n\ +[/U] Kopiuje tylko pliki, które ju¿ istniej¹ w miejscu docelowym\n\ +[/R] Zastêpuje pliki tylko do odczytu\n\ +[/H] Kopiuje równie¿ pliki ukryte i systemowe\n\ +[/C] Kontynuuje nawet je¿eli podczas kopiowania wystêpi³y b³êdy\n\ +[/A] Kopiuje tylko pliki z atrybutem archiwalny\n\ +[/M] Kopiuje tylko pliki z atrybutem archiwalny i usuwa ten atrybut\n\ +[/D | /D:m-d-y] Kopiuje tylko nowe pliki lub te zmodifikowane po podanej dacie.\n\ +\t\tJe¿eli nie podano ¿adnej daty, to kopiowane s¹ pliki, które s¹\n\ +\t\tnowsze ni¿ w katalogu docelowym\n\n" + +} diff --git a/reactos/base/applications/cmdutils/xcopy/Ru.rc b/reactos/base/applications/cmdutils/xcopy/Ru.rc new file mode 100644 index 00000000000..9c4d4e2c33e --- /dev/null +++ b/reactos/base/applications/cmdutils/xcopy/Ru.rc @@ -0,0 +1,82 @@ +/* + * XCOPY - Wine-compatible xcopy program + * Russian language support + * + * Copyright (C) 2007 J. Edmeades + * Copyright (C) 2007 Kirill K. Smirnov + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + + +LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT + +STRINGTABLE +{ + STRING_INVPARMS, +"Íåäîïóñòèìîå ÷èñëî ïàðàìåòðîâ - ïîïðîáóéòå 'xcopy /?' äëÿ ïîëó÷åíèÿ\n\ +ïîäðîáíîãî îïèñàíèÿ.\n" + STRING_INVPARM, +"Íåäîïóñòèìûé ïàðàìåòð '%s' - ïîïðîáóéòå 'xcopy /?' äëÿ ïîëó÷åíèÿ ïîäðîáíîãî\n\ +îïèñàíèÿ.\n" + STRING_PAUSE, "Íàæìèòå êëàâèøó , ÷òîáû íà÷àòü êîïèðîâàíèå.\n" + STRING_SIMCOPY, "%d ôàéë(îâ) áûëî áû ñêîïèðîâàíî.\n" + STRING_COPY, "%d ôàéë(îâ) ñêîïèðîâàíî.\n" + STRING_QISDIR, "'%s' ÿâëÿåòñÿ ôàéëîì èëè ïàïêîé?\n" \ + "(F - Ôàéë, D - Ïàïêà)\n" + STRING_SRCPROMPT,"%s? (Yes|No)\n" + STRING_OVERWRITE,"Ïåðåïèñàòü %s? (Yes|No|All)\n" + STRING_COPYFAIL, "Ïðè êîïèðîâàíèè '%s' â '%s' ïðîèçîøëà îøèáêà: %d\n" + STRING_OPENFAIL, "Íåâîçìîæíî îòêðûòü '%s'\n" + STRING_READFAIL, "Ïðè ÷òåíèè '%s' ïðîèçîøëà îøèáêà\n" + STRING_YES_CHAR, "Y" + STRING_NO_CHAR, "N" + STRING_ALL_CHAR, "A" + STRING_FILE_CHAR,"F" + STRING_DIR_CHAR, "D" + + STRING_HELP, +"XCOPY - Êîïèðóåò ôàéëû è äåðåâüÿ ïàïîê\n\ +\n\ +Ñèíòàêñèñ:\n\ +XCOPY source [dest] [/I] [/S] [/Q] [/F] [/L] [/W] [/T] [/N] [/U] \n\ +\t [/R] [/H] [/C] [/P] [/A] [/M] [/E] [/D] [/Y] [/-Y]\n\ +\n\ +Ãäå:\n\ +\n\ +[/I] Åñëè êîíå÷íàÿ ïàïêà îòñóòñòâóåò è êîïèðóåòñÿ áîëåå îäíîãî ôàéëà, \n\ + òî ïðåäïîëàãàåòñÿ ïàïêà â êà÷åñòâå ìåñòà íàçíà÷åíèÿ.\n\ +[/S] Êîïèðóåò ïàïêè è ïîäïàïêè.\n\ +[/E] Êîïèðóåò ïàïêè è ïîäïàïêè, âêëþ÷àÿ ïóñòûå.\n\ +[/Q] Íå îòîáðàæàåò èìåíà êîïèðóåìûõ ôàéëîâ.\n\ +[/F] Îòîáðàæàåò ïîëíûå èìåíà èñõîäíûõ è êîíå÷íûõ ôàéëîâ.\n\ +[/L] Âûâîäèò ñïèñîê ôàéëîâ, êîòîðûå áóäóò ñêîïèðîâàíû.\n\ +[/W] Çàïðàøèâàåò ïîäòâåðæäåíèå ïåðåä íà÷àëîì êîïèðîâàíèÿ.\n\ +[/T] Ñîçäàåò ñòðóêòóðó ïàïîê, íî íå êîïèðóåò ôàéëû.\n\ +[/Y] Ïîäàâëÿåò çàïðîñ íà ïîäòâåðæäåíèå ïåðåçàïèñè ôàéëîâ.\n\ +[/-Y] Çàïðàøèâàåò ïîäòâåðæäåíèå íà ïåðåçàïèñü ôàéëîâ.\n\ +[/P] Çàïðàøèâàåò ïîäòâåðæäåíèå äëÿ êàæäîãî êîïèðóåìîãî ôàéëà.\n\ +[/N] Èñïîëüçóåò êîðîòêèå èìåíà ôàéëîâ ïðè êîïèðîâàíèè.\n\ +[/U] Êîïèðóåò òîëüêî òå ôàéëû, êîòîðûå óæå ñóùåñòâóþò â êîíå÷íîé ïàïêå.\n\ +[/R] Ïåðåçàïèñûâàåò ôàéëû, äîñòóïíûå òîëüêî äëÿ ÷òåíèÿ.\n\ +[/H] Êîïèðóåò ñêðûòûå è ñèñòåìíûå ôàéëû.\n\ +[/C] Ïðîäîëæàåò ðàáîòó, äàæå åñëè ïðîèçîøëà îøèáêà.\n\ +[/A] Êîïèðóåò òîëüêî òå ôàéëû, äëÿ êîòîðûõ óñòàíîâëåí àòðèáóò \"àðõèâíûé\". \n\ +[/M] Êîïèðóåò òîëüêî òå ôàéëû, äëÿ êîòîðûõ óñòàíîâëåí àòðèáóò \"àðõèâíûé\",\n\ + ïðè ýòîì àòðèáóò óäàëÿåòñÿ.\n\ +[/D | /D:m-d-y] Êîïèðóåò òîëüêî íîâûå ôàéëû èëè òå, êîòîðûå áûëè èçìåíåíû\n\ + ïîñëå óêàçàííîé äàòû. Åñëè äàòà íå óêàçàíà, êîïèðóåò òîëüêî\n\ + òå ôàéëû, êîòîðûå íîâåå â èñõîäíîé ïàïêå.\n" +} diff --git a/reactos/base/applications/cmdutils/xcopy/rsrc.rc b/reactos/base/applications/cmdutils/xcopy/rsrc.rc new file mode 100644 index 00000000000..234a4cbb15a --- /dev/null +++ b/reactos/base/applications/cmdutils/xcopy/rsrc.rc @@ -0,0 +1,28 @@ +/* + * Copyright 2007 Jason Edmeades + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include + +#include "xcopy.h" + +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL + +#include "En.rc" +#include "Ko.rc" +#include "Pl.rc" +#include "Ru.rc" diff --git a/reactos/base/applications/cmdutils/xcopy/xcopy.c b/reactos/base/applications/cmdutils/xcopy/xcopy.c new file mode 100644 index 00000000000..a88a0ad2b1c --- /dev/null +++ b/reactos/base/applications/cmdutils/xcopy/xcopy.c @@ -0,0 +1,1041 @@ +/* + * XCOPY - Wine-compatible xcopy program + * + * Copyright (C) 2007 J. Edmeades + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/* + * FIXME: + * This should now support all options listed in the xcopy help from + * windows XP except: + * /Z - Copy from network drives in restartable mode + * /X - Copy file audit settings (sets /O) + * /O - Copy file ownership + ACL info + * /G - Copy encrypted files to unencrypted destination + * /V - Verifies files + */ + +/* + * Notes: + * Apparently, valid return codes are: + * 0 - OK + * 1 - No files found to copy + * 2 - CTRL+C during copy + * 4 - Initialization error, or invalid source specification + * 5 - Disk write error + */ + + +#include +#include +#include +#include "xcopy.h" + +WINE_DEFAULT_DEBUG_CHANNEL(xcopy); + +/* Prototypes */ +static int XCOPY_ProcessSourceParm(WCHAR *suppliedsource, WCHAR *stem, + WCHAR *spec, DWORD flags); +static int XCOPY_ProcessDestParm(WCHAR *supplieddestination, WCHAR *stem, + WCHAR *spec, WCHAR *srcspec, DWORD flags); +static int XCOPY_DoCopy(WCHAR *srcstem, WCHAR *srcspec, + WCHAR *deststem, WCHAR *destspec, + DWORD flags); +static BOOL XCOPY_CreateDirectory(const WCHAR* path); +static BOOL XCOPY_ProcessExcludeList(WCHAR* parms); +static BOOL XCOPY_ProcessExcludeFile(WCHAR* filename, WCHAR* endOfName); +static WCHAR *XCOPY_LoadMessage(UINT id); +static void XCOPY_FailMessage(DWORD err); +static int XCOPY_wprintf(const WCHAR *format, ...); + +/* Typedefs */ +typedef struct _EXCLUDELIST +{ + struct _EXCLUDELIST *next; + WCHAR *name; +} EXCLUDELIST; + + +/* Global variables */ +static ULONG filesCopied = 0; /* Number of files copied */ +static EXCLUDELIST *excludeList = NULL; /* Excluded strings list */ +static FILETIME dateRange; /* Date range to copy after*/ +static const WCHAR wchr_slash[] = {'\\', 0}; +static const WCHAR wchr_star[] = {'*', 0}; +static const WCHAR wchr_dot[] = {'.', 0}; +static const WCHAR wchr_dotdot[] = {'.', '.', 0}; + +/* Constants (Mostly for widechars) */ + + +/* To minimize stack usage during recursion, some temporary variables + made global */ +static WCHAR copyFrom[MAX_PATH]; +static WCHAR copyTo[MAX_PATH]; + + +/* ========================================================================= + main - Main entrypoint for the xcopy command + + Processes the args, and drives the actual copying + ========================================================================= */ +int wmain (int argc, WCHAR *argvW[]) +{ + int rc = 0; + WCHAR suppliedsource[MAX_PATH] = {0}; /* As supplied on the cmd line */ + WCHAR supplieddestination[MAX_PATH] = {0}; + WCHAR sourcestem[MAX_PATH] = {0}; /* Stem of source */ + WCHAR sourcespec[MAX_PATH] = {0}; /* Filespec of source */ + WCHAR destinationstem[MAX_PATH] = {0}; /* Stem of destination */ + WCHAR destinationspec[MAX_PATH] = {0}; /* Filespec of destination */ + WCHAR copyCmd[MAXSTRING]; /* COPYCMD env var */ + DWORD flags = 0; /* Option flags */ + const WCHAR PROMPTSTR1[] = {'/', 'Y', 0}; + const WCHAR PROMPTSTR2[] = {'/', 'y', 0}; + const WCHAR COPYCMD[] = {'C', 'O', 'P', 'Y', 'C', 'M', 'D', 0}; + const WCHAR EXCLUDE[] = {'E', 'X', 'C', 'L', 'U', 'D', 'E', ':', 0}; + + /* + * Parse the command line + */ + + /* Confirm at least one parameter */ + if (argc < 2) { + XCOPY_wprintf(XCOPY_LoadMessage(STRING_INVPARMS)); + return RC_INITERROR; + } + + /* Preinitialize flags based on COPYCMD */ + if (GetEnvironmentVariable(COPYCMD, copyCmd, MAXSTRING)) { + if (wcsstr(copyCmd, PROMPTSTR1) != NULL || + wcsstr(copyCmd, PROMPTSTR2) != NULL) { + flags |= OPT_NOPROMPT; + } + } + + /* FIXME: On UNIX, files starting with a '.' are treated as hidden under + wine, but on windows these can be normal files. At least one installer + uses files such as .packlist and (validly) expects them to be copied. + Under wine, if we do not copy hidden files by default then they get + lose */ + flags |= OPT_COPYHIDSYS; + + /* Skip first arg, which is the program name */ + argvW++; + + while (argc > 1) + { + argc--; + WINE_TRACE("Processing Arg: '%s'\n", wine_dbgstr_w(*argvW)); + + /* First non-switch parameter is source, second is destination */ + if (*argvW[0] != '/') { + if (suppliedsource[0] == 0x00) { + lstrcpyW(suppliedsource, *argvW); + } else if (supplieddestination[0] == 0x00) { + lstrcpyW(supplieddestination, *argvW); + } else { + XCOPY_wprintf(XCOPY_LoadMessage(STRING_INVPARMS)); + return RC_INITERROR; + } + } else { + /* Process all the switch options + Note: Windows docs say /P prompts when dest is created + but tests show it is done for each src file + regardless of the destination */ + switch (toupper(argvW[0][1])) { + case 'I': flags |= OPT_ASSUMEDIR; break; + case 'S': flags |= OPT_RECURSIVE; break; + case 'Q': flags |= OPT_QUIET; break; + case 'F': flags |= OPT_FULL; break; + case 'L': flags |= OPT_SIMULATE; break; + case 'W': flags |= OPT_PAUSE; break; + case 'T': flags |= OPT_NOCOPY | OPT_RECURSIVE; break; + case 'Y': flags |= OPT_NOPROMPT; break; + case 'N': flags |= OPT_SHORTNAME; break; + case 'U': flags |= OPT_MUSTEXIST; break; + case 'R': flags |= OPT_REPLACEREAD; break; + case 'H': flags |= OPT_COPYHIDSYS; break; + case 'C': flags |= OPT_IGNOREERRORS; break; + case 'P': flags |= OPT_SRCPROMPT; break; + case 'A': flags |= OPT_ARCHIVEONLY; break; + case 'M': flags |= OPT_ARCHIVEONLY | + OPT_REMOVEARCH; break; + + /* E can be /E or /EXCLUDE */ + case 'E': if (CompareString (LOCALE_USER_DEFAULT, + NORM_IGNORECASE | SORT_STRINGSORT, + &argvW[0][1], 8, + EXCLUDE, -1) == 2) { + if (XCOPY_ProcessExcludeList(&argvW[0][9])) { + XCOPY_FailMessage(ERROR_INVALID_PARAMETER); + return RC_INITERROR; + } else flags |= OPT_EXCLUDELIST; + } else flags |= OPT_EMPTYDIR | OPT_RECURSIVE; + break; + + /* D can be /D or /D: */ + case 'D': if ((argvW[0][2])==':' && isdigit(argvW[0][3])) { + SYSTEMTIME st; + WCHAR *pos = &argvW[0][3]; + BOOL isError = FALSE; + memset(&st, 0x00, sizeof(st)); + + /* Parse the arg : Month */ + st.wMonth = _wtol(pos); + while (*pos && isdigit(*pos)) pos++; + if (*pos++ != '-') isError = TRUE; + + /* Parse the arg : Day */ + if (!isError) { + st.wDay = _wtol(pos); + while (*pos && isdigit(*pos)) pos++; + if (*pos++ != '-') isError = TRUE; + } + + /* Parse the arg : Day */ + if (!isError) { + st.wYear = _wtol(pos); + if (st.wYear < 100) st.wYear+=2000; + } + + if (!isError && SystemTimeToFileTime(&st, &dateRange)) { + SYSTEMTIME st; + WCHAR datestring[32], timestring[32]; + + flags |= OPT_DATERANGE; + + /* Debug info: */ + FileTimeToSystemTime (&dateRange, &st); + GetDateFormat (0, DATE_SHORTDATE, &st, NULL, datestring, + sizeof(datestring)); + GetTimeFormat (0, TIME_NOSECONDS, &st, + NULL, timestring, sizeof(timestring)); + + WINE_TRACE("Date being used is: %s %s\n", + wine_dbgstr_w(datestring), wine_dbgstr_w(timestring)); + } else { + XCOPY_FailMessage(ERROR_INVALID_PARAMETER); + return RC_INITERROR; + } + } else { + flags |= OPT_DATENEWER; + } + break; + + case '-': if (toupper(argvW[0][2])=='Y') + flags &= ~OPT_NOPROMPT; break; + case '?': XCOPY_wprintf(XCOPY_LoadMessage(STRING_HELP)); + return RC_OK; + default: + WINE_TRACE("Unhandled parameter '%s'\n", wine_dbgstr_w(*argvW)); + XCOPY_wprintf(XCOPY_LoadMessage(STRING_INVPARM), *argvW); + return RC_INITERROR; + } + } + argvW++; + } + + /* Default the destination if not supplied */ + if (supplieddestination[0] == 0x00) + lstrcpyW(supplieddestination, wchr_dot); + + /* Trace out the supplied information */ + WINE_TRACE("Supplied parameters:\n"); + WINE_TRACE("Source : '%s'\n", wine_dbgstr_w(suppliedsource)); + WINE_TRACE("Destination : '%s'\n", wine_dbgstr_w(supplieddestination)); + + /* Extract required information from source specification */ + rc = XCOPY_ProcessSourceParm(suppliedsource, sourcestem, sourcespec, flags); + + /* Extract required information from destination specification */ + rc = XCOPY_ProcessDestParm(supplieddestination, destinationstem, + destinationspec, sourcespec, flags); + + /* Trace out the resulting information */ + WINE_TRACE("Resolved parameters:\n"); + WINE_TRACE("Source Stem : '%s'\n", wine_dbgstr_w(sourcestem)); + WINE_TRACE("Source Spec : '%s'\n", wine_dbgstr_w(sourcespec)); + WINE_TRACE("Dest Stem : '%s'\n", wine_dbgstr_w(destinationstem)); + WINE_TRACE("Dest Spec : '%s'\n", wine_dbgstr_w(destinationspec)); + + /* Pause if necessary */ + if (flags & OPT_PAUSE) { + DWORD count; + char pausestr[10]; + + XCOPY_wprintf(XCOPY_LoadMessage(STRING_PAUSE)); + ReadFile (GetStdHandle(STD_INPUT_HANDLE), pausestr, sizeof(pausestr), + &count, NULL); + } + + /* Now do the hard work... */ + rc = XCOPY_DoCopy(sourcestem, sourcespec, + destinationstem, destinationspec, + flags); + + /* Clear up exclude list allocated memory */ + while (excludeList) { + EXCLUDELIST *pos = excludeList; + excludeList = excludeList -> next; + HeapFree(GetProcessHeap(), 0, pos->name); + HeapFree(GetProcessHeap(), 0, pos); + } + + /* Finished - print trailer and exit */ + if (flags & OPT_SIMULATE) { + XCOPY_wprintf(XCOPY_LoadMessage(STRING_SIMCOPY), filesCopied); + } else if (!(flags & OPT_NOCOPY)) { + XCOPY_wprintf(XCOPY_LoadMessage(STRING_COPY), filesCopied); + } + if (rc == RC_OK && filesCopied == 0) rc = RC_NOFILES; + return rc; + +} + + +/* ========================================================================= + XCOPY_ProcessSourceParm - Takes the supplied source parameter, and + converts it into a stem and a filespec + ========================================================================= */ +static int XCOPY_ProcessSourceParm(WCHAR *suppliedsource, WCHAR *stem, + WCHAR *spec, DWORD flags) +{ + WCHAR actualsource[MAX_PATH]; + WCHAR *starPos; + WCHAR *questPos; + DWORD attribs; + + /* + * Validate the source, expanding to full path ensuring it exists + */ + if (GetFullPathName(suppliedsource, MAX_PATH, actualsource, NULL) == 0) { + WINE_FIXME("Unexpected failure expanding source path (%d)\n", GetLastError()); + return RC_INITERROR; + } + + /* If full names required, convert to using the full path */ + if (flags & OPT_FULL) { + lstrcpyW(suppliedsource, actualsource); + } + + /* + * Work out the stem of the source + */ + + /* If a directory is supplied, use that as-is (either fully or + partially qualified) + If a filename is supplied + a directory or drive path, use that + as-is + Otherwise + If no directory or path specified, add eg. C: + stem is Drive/Directory is bit up to last \ (or first :) + spec is bit after that */ + + starPos = wcschr(suppliedsource, '*'); + questPos = wcschr(suppliedsource, '?'); + if (starPos || questPos) { + attribs = 0x00; /* Ensures skips invalid or directory check below */ + } else { + attribs = GetFileAttributes(actualsource); + } + + if (attribs == INVALID_FILE_ATTRIBUTES) { + XCOPY_FailMessage(GetLastError()); + return RC_INITERROR; + + /* Directory: + stem should be exactly as supplied plus a '\', unless it was + eg. C: in which case no slash required */ + } else if (attribs & FILE_ATTRIBUTE_DIRECTORY) { + WCHAR lastChar; + + WINE_TRACE("Directory supplied\n"); + lstrcpyW(stem, suppliedsource); + lastChar = stem[lstrlenW(stem)-1]; + if (lastChar != '\\' && lastChar != ':') { + lstrcatW(stem, wchr_slash); + } + lstrcpyW(spec, wchr_star); + + /* File or wildcard search: + stem should be: + Up to and including last slash if directory path supplied + If c:filename supplied, just the c: + Otherwise stem should be the current drive letter + ':' */ + } else { + WCHAR *lastDir; + + WINE_TRACE("Filename supplied\n"); + lastDir = wcsrchr(suppliedsource, '\\'); + + if (lastDir) { + lstrcpyW(stem, suppliedsource); + stem[(lastDir-suppliedsource) + 1] = 0x00; + lstrcpyW(spec, (lastDir+1)); + } else if (suppliedsource[1] == ':') { + lstrcpyW(stem, suppliedsource); + stem[2] = 0x00; + lstrcpyW(spec, suppliedsource+2); + } else { + WCHAR curdir[MAXSTRING]; + GetCurrentDirectory (sizeof(curdir), curdir); + stem[0] = curdir[0]; + stem[1] = curdir[1]; + stem[2] = 0x00; + lstrcpyW(spec, suppliedsource); + } + } + + return RC_OK; +} + +/* ========================================================================= + XCOPY_ProcessDestParm - Takes the supplied destination parameter, and + converts it into a stem + ========================================================================= */ +static int XCOPY_ProcessDestParm(WCHAR *supplieddestination, WCHAR *stem, WCHAR *spec, + WCHAR *srcspec, DWORD flags) +{ + WCHAR actualdestination[MAX_PATH]; + DWORD attribs; + BOOL isDir = FALSE; + + /* + * Validate the source, expanding to full path ensuring it exists + */ + if (GetFullPathName(supplieddestination, MAX_PATH, actualdestination, NULL) == 0) { + WINE_FIXME("Unexpected failure expanding source path (%d)\n", GetLastError()); + return RC_INITERROR; + } + + /* Destination is either a directory or a file */ + attribs = GetFileAttributes(actualdestination); + + if (attribs == INVALID_FILE_ATTRIBUTES) { + + /* If /I supplied and wildcard copy, assume directory */ + if (flags & OPT_ASSUMEDIR && + (wcschr(srcspec, '?') || wcschr(srcspec, '*'))) { + + isDir = TRUE; + + } else { + DWORD count; + char answer[10] = ""; + WCHAR fileChar[2]; + WCHAR dirChar[2]; + + /* Read the F and D characters from the resource file */ + wcscpy(fileChar, XCOPY_LoadMessage(STRING_FILE_CHAR)); + wcscpy(dirChar, XCOPY_LoadMessage(STRING_DIR_CHAR)); + + while (answer[0] != fileChar[0] && answer[0] != dirChar[0]) { + XCOPY_wprintf(XCOPY_LoadMessage(STRING_QISDIR), supplieddestination); + + ReadFile(GetStdHandle(STD_INPUT_HANDLE), answer, sizeof(answer), &count, NULL); + WINE_TRACE("User answer %c\n", answer[0]); + + answer[0] = toupper(answer[0]); + } + + if (answer[0] == dirChar[0]) { + isDir = TRUE; + } else { + isDir = FALSE; + } + } + } else { + isDir = (attribs & FILE_ATTRIBUTE_DIRECTORY); + } + + if (isDir) { + lstrcpyW(stem, actualdestination); + *spec = 0x00; + + /* Ensure ends with a '\' */ + if (stem[lstrlenW(stem)-1] != '\\') { + lstrcatW(stem, wchr_slash); + } + + } else { + WCHAR drive[MAX_PATH]; + WCHAR dir[MAX_PATH]; + WCHAR fname[MAX_PATH]; + WCHAR ext[MAX_PATH]; + _wsplitpath(actualdestination, drive, dir, fname, ext); + lstrcpyW(stem, drive); + lstrcatW(stem, dir); + lstrcpyW(spec, fname); + lstrcatW(spec, ext); + } + return RC_OK; +} + +/* ========================================================================= + XCOPY_DoCopy - Recursive function to copy files based on input parms + of a stem and a spec + + This works by using FindFirstFile supplying the source stem and spec. + If results are found, any non-directory ones are processed + Then, if /S or /E is supplied, another search is made just for + directories, and this function is called again for that directory + + ========================================================================= */ +static int XCOPY_DoCopy(WCHAR *srcstem, WCHAR *srcspec, + WCHAR *deststem, WCHAR *destspec, + DWORD flags) +{ + WIN32_FIND_DATA *finddata; + HANDLE h; + BOOL findres = TRUE; + WCHAR *inputpath, *outputpath; + BOOL copiedFile = FALSE; + DWORD destAttribs, srcAttribs; + BOOL skipFile; + + /* Allocate some working memory on heap to minimize footprint */ + finddata = HeapAlloc(GetProcessHeap(), 0, sizeof(WIN32_FIND_DATA)); + inputpath = HeapAlloc(GetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR)); + outputpath = HeapAlloc(GetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR)); + + /* Build the search info into a single parm */ + lstrcpyW(inputpath, srcstem); + lstrcatW(inputpath, srcspec); + + /* Search 1 - Look for matching files */ + h = FindFirstFile(inputpath, finddata); + while (h != INVALID_HANDLE_VALUE && findres) { + + skipFile = FALSE; + + /* Ignore . and .. */ + if (lstrcmpW(finddata->cFileName, wchr_dot)==0 || + lstrcmpW(finddata->cFileName, wchr_dotdot)==0 || + finddata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + + WINE_TRACE("Skipping directory, . or .. (%s)\n", wine_dbgstr_w(finddata->cFileName)); + } else { + + /* Get the filename information */ + lstrcpyW(copyFrom, srcstem); + if (flags & OPT_SHORTNAME) { + lstrcatW(copyFrom, finddata->cAlternateFileName); + } else { + lstrcatW(copyFrom, finddata->cFileName); + } + + lstrcpyW(copyTo, deststem); + if (*destspec == 0x00) { + if (flags & OPT_SHORTNAME) { + lstrcatW(copyTo, finddata->cAlternateFileName); + } else { + lstrcatW(copyTo, finddata->cFileName); + } + } else { + lstrcatW(copyTo, destspec); + } + + /* Do the copy */ + WINE_TRACE("ACTION: Copy '%s' -> '%s'\n", wine_dbgstr_w(copyFrom), + wine_dbgstr_w(copyTo)); + if (!copiedFile && !(flags & OPT_SIMULATE)) XCOPY_CreateDirectory(deststem); + + /* See if allowed to copy it */ + srcAttribs = GetFileAttributesW(copyFrom); + WINE_TRACE("Source attribs: %d\n", srcAttribs); + + if ((srcAttribs & FILE_ATTRIBUTE_HIDDEN) || + (srcAttribs & FILE_ATTRIBUTE_SYSTEM)) { + + if (!(flags & OPT_COPYHIDSYS)) { + skipFile = TRUE; + } + } + + if (!(srcAttribs & FILE_ATTRIBUTE_ARCHIVE) && + (flags & OPT_ARCHIVEONLY)) { + skipFile = TRUE; + } + + /* See if file exists */ + destAttribs = GetFileAttributesW(copyTo); + WINE_TRACE("Dest attribs: %d\n", srcAttribs); + + /* Check date ranges if a destination file already exists */ + if (!skipFile && (flags & OPT_DATERANGE) && + (CompareFileTime(&finddata->ftLastWriteTime, &dateRange) < 0)) { + WINE_TRACE("Skipping file as modified date too old\n"); + skipFile = TRUE; + } + + /* If just /D supplied, only overwrite if src newer than dest */ + if (!skipFile && (flags & OPT_DATENEWER) && + (destAttribs != INVALID_FILE_ATTRIBUTES)) { + HANDLE h = CreateFile(copyTo, GENERIC_READ, FILE_SHARE_READ, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, + NULL); + if (h != INVALID_HANDLE_VALUE) { + FILETIME writeTime; + GetFileTime(h, NULL, NULL, &writeTime); + + if (CompareFileTime(&finddata->ftLastWriteTime, &writeTime) <= 0) { + WINE_TRACE("Skipping file as dest newer or same date\n"); + skipFile = TRUE; + } + CloseHandle(h); + } + } + + /* See if exclude list provided. Note since filenames are case + insensitive, need to uppercase the filename before doing + strstr */ + if (!skipFile && (flags & OPT_EXCLUDELIST)) { + EXCLUDELIST *pos = excludeList; + WCHAR copyFromUpper[MAX_PATH]; + + /* Uppercase source filename */ + lstrcpyW(copyFromUpper, copyFrom); + CharUpperBuff(copyFromUpper, lstrlenW(copyFromUpper)); + + /* Loop through testing each exclude line */ + while (pos) { + if (wcsstr(copyFromUpper, pos->name) != NULL) { + WINE_TRACE("Skipping file as matches exclude '%s'\n", + wine_dbgstr_w(pos->name)); + skipFile = TRUE; + pos = NULL; + } else { + pos = pos->next; + } + } + } + + /* Prompt each file if necessary */ + if (!skipFile && (flags & OPT_SRCPROMPT)) { + DWORD count; + char answer[10]; + BOOL answered = FALSE; + WCHAR yesChar[2]; + WCHAR noChar[2]; + + /* Read the Y and N characters from the resource file */ + wcscpy(yesChar, XCOPY_LoadMessage(STRING_YES_CHAR)); + wcscpy(noChar, XCOPY_LoadMessage(STRING_NO_CHAR)); + + while (!answered) { + XCOPY_wprintf(XCOPY_LoadMessage(STRING_SRCPROMPT), copyFrom); + ReadFile (GetStdHandle(STD_INPUT_HANDLE), answer, sizeof(answer), + &count, NULL); + + answered = TRUE; + if (toupper(answer[0]) == noChar[0]) + skipFile = TRUE; + else if (toupper(answer[0]) != yesChar[0]) + answered = FALSE; + } + } + + if (!skipFile && + destAttribs != INVALID_FILE_ATTRIBUTES && !(flags & OPT_NOPROMPT)) { + DWORD count; + char answer[10]; + BOOL answered = FALSE; + WCHAR yesChar[2]; + WCHAR allChar[2]; + WCHAR noChar[2]; + + /* Read the A,Y and N characters from the resource file */ + wcscpy(yesChar, XCOPY_LoadMessage(STRING_YES_CHAR)); + wcscpy(allChar, XCOPY_LoadMessage(STRING_ALL_CHAR)); + wcscpy(noChar, XCOPY_LoadMessage(STRING_NO_CHAR)); + + while (!answered) { + XCOPY_wprintf(XCOPY_LoadMessage(STRING_OVERWRITE), copyTo); + ReadFile (GetStdHandle(STD_INPUT_HANDLE), answer, sizeof(answer), + &count, NULL); + + answered = TRUE; + if (toupper(answer[0]) == allChar[0]) + flags |= OPT_NOPROMPT; + else if (toupper(answer[0]) == noChar[0]) + skipFile = TRUE; + else if (toupper(answer[0]) != yesChar[0]) + answered = FALSE; + } + } + + /* See if it has to exist! */ + if (destAttribs == INVALID_FILE_ATTRIBUTES && (flags & OPT_MUSTEXIST)) { + skipFile = TRUE; + } + + /* Output a status message */ + if (!skipFile) { + if (flags & OPT_QUIET) { + /* Skip message */ + } else if (flags & OPT_FULL) { + const WCHAR infostr[] = {'%', 's', ' ', '-', '>', ' ', + '%', 's', '\n', 0}; + + XCOPY_wprintf(infostr, copyFrom, copyTo); + } else { + const WCHAR infostr[] = {'%', 's', '\n', 0}; + XCOPY_wprintf(infostr, copyFrom); + } + + /* If allowing overwriting of read only files, remove any + write protection */ + if ((destAttribs & FILE_ATTRIBUTE_READONLY) && + (flags & OPT_REPLACEREAD)) { + SetFileAttributes(copyTo, destAttribs & ~FILE_ATTRIBUTE_READONLY); + } + + copiedFile = TRUE; + if (flags & OPT_SIMULATE || flags & OPT_NOCOPY) { + /* Skip copy */ + } else if (CopyFile(copyFrom, copyTo, FALSE) == 0) { + + DWORD error = GetLastError(); + XCOPY_wprintf(XCOPY_LoadMessage(STRING_COPYFAIL), + copyFrom, copyTo, error); + XCOPY_FailMessage(error); + + if (flags & OPT_IGNOREERRORS) { + skipFile = TRUE; + } else { + return RC_WRITEERROR; + } + } + + /* If /M supplied, remove the archive bit after successful copy */ + if (!skipFile) { + if ((srcAttribs & FILE_ATTRIBUTE_ARCHIVE) && + (flags & OPT_REMOVEARCH)) { + SetFileAttributes(copyFrom, (srcAttribs & ~FILE_ATTRIBUTE_ARCHIVE)); + } + filesCopied++; + } + } + } + + /* Find next file */ + findres = FindNextFile(h, finddata); + } + FindClose(h); + + /* Search 2 - do subdirs */ + if (flags & OPT_RECURSIVE) { + lstrcpyW(inputpath, srcstem); + lstrcatW(inputpath, wchr_star); + findres = TRUE; + WINE_TRACE("Processing subdirs with spec: %s\n", wine_dbgstr_w(inputpath)); + + h = FindFirstFile(inputpath, finddata); + while (h != INVALID_HANDLE_VALUE && findres) { + + /* Only looking for dirs */ + if ((finddata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && + (lstrcmpW(finddata->cFileName, wchr_dot) != 0) && + (lstrcmpW(finddata->cFileName, wchr_dotdot) != 0)) { + + WINE_TRACE("Handling subdir: %s\n", wine_dbgstr_w(finddata->cFileName)); + + /* Make up recursive information */ + lstrcpyW(inputpath, srcstem); + lstrcatW(inputpath, finddata->cFileName); + lstrcatW(inputpath, wchr_slash); + + lstrcpyW(outputpath, deststem); + if (*destspec == 0x00) { + lstrcatW(outputpath, finddata->cFileName); + + /* If /E is supplied, create the directory now */ + if ((flags & OPT_EMPTYDIR) && + !(flags & OPT_SIMULATE)) + XCOPY_CreateDirectory(outputpath); + + lstrcatW(outputpath, wchr_slash); + } + + XCOPY_DoCopy(inputpath, srcspec, outputpath, destspec, flags); + } + + /* Find next one */ + findres = FindNextFile(h, finddata); + } + } + + /* free up memory */ + HeapFree(GetProcessHeap(), 0, finddata); + HeapFree(GetProcessHeap(), 0, inputpath); + HeapFree(GetProcessHeap(), 0, outputpath); + + return 0; +} + +/* ========================================================================= + * Routine copied from cmd.exe md command - + * This works recursivly. so creating dir1\dir2\dir3 will create dir1 and + * dir2 if they do not already exist. + * ========================================================================= */ +static BOOL XCOPY_CreateDirectory(const WCHAR* path) +{ + int len; + WCHAR *new_path; + BOOL ret = TRUE; + + new_path = HeapAlloc(GetProcessHeap(),0, sizeof(WCHAR) * (lstrlenW(path)+1)); + lstrcpyW(new_path,path); + + while ((len = lstrlenW(new_path)) && new_path[len - 1] == '\\') + new_path[len - 1] = 0; + + while (!CreateDirectory(new_path,NULL)) + { + WCHAR *slash; + DWORD last_error = GetLastError(); + if (last_error == ERROR_ALREADY_EXISTS) + break; + + if (last_error != ERROR_PATH_NOT_FOUND) + { + ret = FALSE; + break; + } + + if (!(slash = wcsrchr(new_path,'\\')) && ! (slash = wcsrchr(new_path,'/'))) + { + ret = FALSE; + break; + } + + len = slash - new_path; + new_path[len] = 0; + if (!XCOPY_CreateDirectory(new_path)) + { + ret = FALSE; + break; + } + new_path[len] = '\\'; + } + HeapFree(GetProcessHeap(),0,new_path); + return ret; +} + +/* ========================================================================= + * Process the /EXCLUDE: file list, building up a list of substrings to + * avoid copying + * Returns TRUE on any failure + * ========================================================================= */ +static BOOL XCOPY_ProcessExcludeList(WCHAR* parms) { + + WCHAR *filenameStart = parms; + + WINE_TRACE("/EXCLUDE parms: '%s'\n", wine_dbgstr_w(parms)); + excludeList = NULL; + + while (*parms && *parms != ' ' && *parms != '/') { + + /* If found '+' then process the file found so far */ + if (*parms == '+') { + if (XCOPY_ProcessExcludeFile(filenameStart, parms)) { + return TRUE; + } + filenameStart = parms+1; + } + parms++; + } + + if (filenameStart != parms) { + if (XCOPY_ProcessExcludeFile(filenameStart, parms)) { + return TRUE; + } + } + + return FALSE; +} + +/* ========================================================================= + * Process a single file from the /EXCLUDE: file list, building up a list + * of substrings to avoid copying + * Returns TRUE on any failure + * ========================================================================= */ +static BOOL XCOPY_ProcessExcludeFile(WCHAR* filename, WCHAR* endOfName) { + + WCHAR endChar = *endOfName; + WCHAR buffer[MAXSTRING]; + FILE *inFile = NULL; + const WCHAR readTextMode[] = {'r', 't', 0}; + + /* Null terminate the filename (temporarily updates the filename hence + parms not const) */ + *endOfName = 0x00; + + /* Open the file */ + inFile = _wfopen(filename, readTextMode); + if (inFile == NULL) { + XCOPY_wprintf(XCOPY_LoadMessage(STRING_OPENFAIL), filename); + *endOfName = endChar; + return TRUE; + } + + /* Process line by line */ + while (fgetws(buffer, sizeof(buffer), inFile) != NULL) { + EXCLUDELIST *thisEntry; + int length = lstrlenW(buffer); + + /* Strip CRLF */ + buffer[length-1] = 0x00; + + /* If more than CRLF */ + if (length > 1) { + thisEntry = HeapAlloc(GetProcessHeap(), 0, sizeof(EXCLUDELIST)); + thisEntry->next = excludeList; + excludeList = thisEntry; + thisEntry->name = HeapAlloc(GetProcessHeap(), 0, + (length * sizeof(WCHAR))+1); + lstrcpyW(thisEntry->name, buffer); + CharUpperBuff(thisEntry->name, length); + WINE_TRACE("Read line : '%s'\n", wine_dbgstr_w(thisEntry->name)); + } + } + + /* See if EOF or error occurred */ + if (!feof(inFile)) { + XCOPY_wprintf(XCOPY_LoadMessage(STRING_READFAIL), filename); + *endOfName = endChar; + return TRUE; + } + + /* Revert the input string to original form, and cleanup + return */ + *endOfName = endChar; + fclose(inFile); + return FALSE; +} + +/* ========================================================================= + * Load a string from the resource file, handling any error + * Returns string retrieved from resource file + * ========================================================================= */ +static WCHAR *XCOPY_LoadMessage(UINT id) { + static WCHAR msg[MAXSTRING]; + const WCHAR failedMsg[] = {'F', 'a', 'i', 'l', 'e', 'd', '!', 0}; + + if (!LoadString(GetModuleHandle(NULL), id, msg, sizeof(msg))) { + WINE_FIXME("LoadString failed with %d\n", GetLastError()); + lstrcpyW(msg, failedMsg); + } + return msg; +} + +/* ========================================================================= + * Load a string for a system error and writes it to the screen + * Returns string retrieved from resource file + * ========================================================================= */ +static void XCOPY_FailMessage(DWORD err) { + LPWSTR lpMsgBuf; + int status; + + status = FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM, + NULL, err, 0, + (LPTSTR) &lpMsgBuf, 0, NULL); + if (!status) { + WINE_FIXME("FIXME: Cannot display message for error %d, status %d\n", + err, GetLastError()); + } else { + const WCHAR infostr[] = {'%', 's', '\n', 0}; + XCOPY_wprintf(infostr, lpMsgBuf); + LocalFree ((HLOCAL)lpMsgBuf); + } +} + +/* ========================================================================= + * Output a formatted unicode string. Ideally this will go to the console + * and hence required WriteConsoleW to output it, however if file i/o is + * redirected, it needs to be WriteFile'd using OEM (not ANSI) format + * ========================================================================= */ +int XCOPY_wprintf(const WCHAR *format, ...) { + + static WCHAR *output_bufW = NULL; + static char *output_bufA = NULL; + static BOOL toConsole = TRUE; + static BOOL traceOutput = FALSE; +#define MAX_WRITECONSOLE_SIZE 65535 + + va_list parms; + DWORD len, nOut; + DWORD res = 0; + + /* + * Allocate buffer to use when writing to console + * Note: Not freed - memory will be allocated once and released when + * xcopy ends + */ + + if (!output_bufW) output_bufW = HeapAlloc(GetProcessHeap(), 0, + MAX_WRITECONSOLE_SIZE); + if (!output_bufW) { + WINE_FIXME("Out of memory - could not allocate 2 x 64K buffers\n"); + return 0; + } + + /* Use wvsprintf to store output into unicode buffer */ + va_start(parms, format); + len = vswprintf(output_bufW, format, parms); + va_end(parms); + + /* Try to write as unicode all the time we think its a console */ + if (toConsole) { + res = WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), + output_bufW, len, &nOut, NULL); + } + + /* If writing to console has failed (ever) we assume its file + i/o so convert to OEM codepage and output */ + if (!res) { + BOOL usedDefaultChar = FALSE; + DWORD convertedChars; + + toConsole = FALSE; + + /* + * Allocate buffer to use when writing to file. Not freed, as above + */ + if (!output_bufA) output_bufA = HeapAlloc(GetProcessHeap(), 0, + MAX_WRITECONSOLE_SIZE); + if (!output_bufA) { + WINE_FIXME("Out of memory - could not allocate 2 x 64K buffers\n"); + return 0; + } + + /* Convert to OEM, then output */ + convertedChars = WideCharToMultiByte(GetConsoleOutputCP(), 0, output_bufW, + len, output_bufA, MAX_WRITECONSOLE_SIZE, + "?", &usedDefaultChar); + WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), output_bufA, convertedChars, + &nOut, FALSE); + } + + /* Trace whether screen or console */ + if (!traceOutput) { + WINE_TRACE("Writing to console? (%d)\n", toConsole); + traceOutput = TRUE; + } + return nOut; +} diff --git a/reactos/base/applications/cmdutils/xcopy/xcopy.h b/reactos/base/applications/cmdutils/xcopy/xcopy.h new file mode 100644 index 00000000000..ee4bd910cde --- /dev/null +++ b/reactos/base/applications/cmdutils/xcopy/xcopy.h @@ -0,0 +1,68 @@ +/* + * XCOPY - Wine-compatible xcopy program + * + * Copyright (C) 2007 J. Edmeades + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/* Local #defines */ +#define RC_OK 0 +#define RC_NOFILES 1 +#define RC_CTRLC 2 +#define RC_INITERROR 4 +#define RC_WRITEERROR 5 + +#define OPT_ASSUMEDIR 0x00000001 +#define OPT_RECURSIVE 0x00000002 +#define OPT_EMPTYDIR 0x00000004 +#define OPT_QUIET 0x00000008 +#define OPT_FULL 0x00000010 +#define OPT_SIMULATE 0x00000020 +#define OPT_PAUSE 0x00000040 +#define OPT_NOCOPY 0x00000080 +#define OPT_NOPROMPT 0x00000100 +#define OPT_SHORTNAME 0x00000200 +#define OPT_MUSTEXIST 0x00000400 +#define OPT_REPLACEREAD 0x00000800 +#define OPT_COPYHIDSYS 0x00001000 +#define OPT_IGNOREERRORS 0x00002000 +#define OPT_SRCPROMPT 0x00004000 +#define OPT_ARCHIVEONLY 0x00008000 +#define OPT_REMOVEARCH 0x00010000 +#define OPT_EXCLUDELIST 0x00020000 +#define OPT_DATERANGE 0x00040000 +#define OPT_DATENEWER 0x00080000 + +#define MAXSTRING 8192 + +/* Translation ids */ +#define STRING_INVPARMS 101 +#define STRING_INVPARM 102 +#define STRING_PAUSE 103 +#define STRING_SIMCOPY 104 +#define STRING_COPY 105 +#define STRING_QISDIR 106 +#define STRING_SRCPROMPT 107 +#define STRING_OVERWRITE 108 +#define STRING_COPYFAIL 109 +#define STRING_OPENFAIL 110 +#define STRING_READFAIL 111 +#define STRING_YES_CHAR 112 +#define STRING_NO_CHAR 113 +#define STRING_ALL_CHAR 114 +#define STRING_FILE_CHAR 115 +#define STRING_DIR_CHAR 116 +#define STRING_HELP 117 diff --git a/reactos/base/applications/cmdutils/xcopy/xcopy.rbuild b/reactos/base/applications/cmdutils/xcopy/xcopy.rbuild new file mode 100644 index 00000000000..5a44d7361c8 --- /dev/null +++ b/reactos/base/applications/cmdutils/xcopy/xcopy.rbuild @@ -0,0 +1,11 @@ + + + + . + kernel32 + advapi32 + user32 + xcopy.c + xcopy.rc + + diff --git a/reactos/base/applications/cmdutils/xcopy/xcopy.rc b/reactos/base/applications/cmdutils/xcopy/xcopy.rc new file mode 100644 index 00000000000..cb4db04093d --- /dev/null +++ b/reactos/base/applications/cmdutils/xcopy/xcopy.rc @@ -0,0 +1,17 @@ +#include +#include + +#include "resource.h" + + +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL + +#define REACTOS_VERSION_DLL +#define REACTOS_STR_FILE_DESCRIPTION "xcopy command\0" +#define REACTOS_STR_INTERNAL_NAME "xcopy\0" +#define REACTOS_STR_ORIGINAL_FILENAME "xcopy.exe\0" +#include + +#include "rsrc.rc" + + -- 2.17.1