Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

440 lines
10 KiB

  1. /*++
  2. Copyright (c) 1998 Intel Corporation
  3. Module Name:
  4. cp.c
  5. Abstract:
  6. Shell app "cp"
  7. Revision History
  8. --*/
  9. #include "shell.h"
  10. #define COPY_SIZE (64*1024)
  11. VOID *CpBuffer;
  12. /*
  13. *
  14. */
  15. EFI_STATUS
  16. InitializeCP (
  17. IN EFI_HANDLE ImageHandle,
  18. IN EFI_SYSTEM_TABLE *SystemTable
  19. );
  20. VOID
  21. CopyCP (
  22. IN SHELL_FILE_ARG *Src,
  23. IN SHELL_FILE_ARG *Dst,
  24. IN BOOLEAN CreateSubDir
  25. );
  26. /*
  27. *
  28. */
  29. EFI_DRIVER_ENTRY_POINT(InitializeCP)
  30. EFI_STATUS
  31. InitializeCP (
  32. IN EFI_HANDLE ImageHandle,
  33. IN EFI_SYSTEM_TABLE *SystemTable
  34. )
  35. {
  36. CHAR16 **Argv;
  37. UINTN Argc;
  38. UINTN Index;
  39. CHAR16 *Dest;
  40. LIST_ENTRY SrcList;
  41. LIST_ENTRY DstList;
  42. LIST_ENTRY *Link;
  43. SHELL_FILE_ARG *SrcArg, *DstArg;
  44. UINTN Len1, Len2;
  45. BOOLEAN CreateSubDir;
  46. /*
  47. * Check to see if the app is to install as a "internal command"
  48. * to the shell
  49. */
  50. InstallInternalShellCommand (
  51. ImageHandle, SystemTable, InitializeCP,
  52. L"cp", /* command */
  53. L"cp file [file] ... [dest]", /* command syntax */
  54. L"Copy files/dirs", /* 1 line descriptor */
  55. NULL /* command help page */
  56. );
  57. /*
  58. * We are no being installed as an internal command driver, initialize
  59. * as an nshell app and run
  60. */
  61. InitializeShellApplication (ImageHandle, SystemTable);
  62. InitializeListHead (&SrcList);
  63. InitializeListHead (&DstList);
  64. CpBuffer = NULL;
  65. CreateSubDir = FALSE;
  66. Argv = SI->Argv;
  67. Argc = SI->Argc;
  68. if (Argc < 2) {
  69. Print (L"cp: no files specified\n");
  70. goto Done;
  71. }
  72. /*
  73. * If there's only 1 argument, then assume the destionation is
  74. * the current directory
  75. */
  76. if (Argc == 2) {
  77. Dest = L".";
  78. } else {
  79. Argc -= 1;
  80. Dest = Argv[Argc];
  81. }
  82. /*
  83. * Expand the source file list
  84. */
  85. for (Index = 1; Index < Argc; Index += 1) {
  86. ShellFileMetaArg (Argv[Index], &SrcList);
  87. }
  88. /*
  89. * Expand the desctionation (had better be only one entry)
  90. */
  91. ShellFileMetaArg (Dest, &DstList);
  92. if (IsListEmpty(&DstList)) {
  93. Print (L"cp: no destionation\n");
  94. goto Done;
  95. }
  96. DstArg = CR(DstList.Flink, SHELL_FILE_ARG, Link, SHELL_FILE_ARG_SIGNATURE);
  97. if (DstArg->Link.Flink != &DstList) {
  98. Print (L"cp: destionation must be 1 location\n");
  99. goto Done;
  100. }
  101. /*
  102. * Verify no unexpected error on the destionation file
  103. */
  104. if (EFI_ERROR(DstArg->Status) && DstArg->Status != EFI_NOT_FOUND) {
  105. Print (L"cp: could not open/create destionation %hs - %r\n", DstArg->FullName, DstArg->Status);
  106. goto Done;
  107. }
  108. /*
  109. * Is there's more then one source file?
  110. */
  111. if (SrcList.Flink->Flink != &SrcList) {
  112. CreateSubDir = TRUE;
  113. if (DstArg->Info && !(DstArg->Info->Attribute & EFI_FILE_DIRECTORY)) {
  114. Print(L"cp: can not copy > 1 source file into single destionation file\n");
  115. goto Done;
  116. }
  117. }
  118. CpBuffer = AllocatePool (COPY_SIZE);
  119. if (!CpBuffer) {
  120. Print(L"cp: out of memory\n");
  121. goto Done;
  122. }
  123. /*
  124. * Copy each file in the SrcList
  125. */
  126. for (Link=SrcList.Flink; Link!=&SrcList; Link=Link->Flink) {
  127. SrcArg = CR(Link, SHELL_FILE_ARG, Link, SHELL_FILE_ARG_SIGNATURE);
  128. if (StriCmp(SrcArg->FileName, DstArg->FileName) == 0) {
  129. Len1 = DevicePathSize(SrcArg->ParentDevicePath);
  130. Len2 = DevicePathSize(DstArg->ParentDevicePath);
  131. if (Len1 == Len2 &&
  132. CompareMem(SrcArg->ParentDevicePath, DstArg->ParentDevicePath, Len1) == 0) {
  133. Print(L"cp: can not copy. src = dest (%hs)\n", SrcArg->FullName);
  134. continue;
  135. }
  136. }
  137. if (EFI_ERROR(SrcArg->Status)) {
  138. Print(L"cp: can not open %hs - %r\n", SrcArg->FullName, SrcArg->Status);
  139. continue;
  140. }
  141. CopyCP (SrcArg, DstArg, CreateSubDir);
  142. }
  143. Done:
  144. if (CpBuffer) {
  145. FreePool (CpBuffer);
  146. CpBuffer = NULL;
  147. }
  148. ShellFreeFileList (&SrcList);
  149. ShellFreeFileList (&DstList);
  150. return EFI_SUCCESS;
  151. }
  152. SHELL_FILE_ARG *
  153. CpCreateChild (
  154. IN SHELL_FILE_ARG *Parent,
  155. IN CHAR16 *FileName,
  156. IN OUT LIST_ENTRY *ListHead
  157. )
  158. {
  159. SHELL_FILE_ARG *Arg;
  160. UINTN Len;
  161. Arg = AllocateZeroPool (sizeof(SHELL_FILE_ARG));
  162. if (!Arg) {
  163. return NULL;
  164. }
  165. Arg->Signature = SHELL_FILE_ARG_SIGNATURE;
  166. Parent->Parent->Open (Parent->Handle, &Arg->Parent, L".", EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE, 0);
  167. Arg->ParentName = StrDuplicate(Parent->FullName);
  168. Arg->FileName = StrDuplicate(FileName);
  169. /* append filename to parent's name to get the file's full name */
  170. Len = StrLen(Arg->ParentName);
  171. if (Len && Arg->ParentName[Len-1] == '\\') {
  172. Len -= 1;
  173. }
  174. Arg->FullName = PoolPrint(L"%.*s\\%s", Len, Arg->ParentName, FileName);
  175. InsertTailList (ListHead, &Arg->Link);
  176. return Arg;
  177. }
  178. VOID
  179. CopyCP (
  180. IN SHELL_FILE_ARG *Src,
  181. IN SHELL_FILE_ARG *Dst,
  182. IN BOOLEAN CreateSubDir
  183. )
  184. {
  185. EFI_FILE_INFO *Info;
  186. EFI_STATUS Status;
  187. UINTN Size, WriteSize;
  188. LIST_ENTRY Cleanup;
  189. UINT64 SrcAttr, DstAttr;
  190. SHELL_FILE_ARG *NewSrc;
  191. SHELL_FILE_ARG *NewDst;
  192. if (!Src || !Dst) {
  193. Print(L"cp: out of memory\n");
  194. return ;
  195. }
  196. /*
  197. * N.B. we alloc our own shell_file_arg's to recurs, but we only
  198. * fill in some of the fields
  199. */
  200. Info = (EFI_FILE_INFO *) CpBuffer;
  201. InitializeListHead (&Cleanup);
  202. /*
  203. * If the src file is not open, open it
  204. */
  205. if (!Src->Handle) {
  206. Status = Src->Parent->Open (
  207. Src->Parent,
  208. &Src->Handle,
  209. Src->FileName,
  210. EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE,
  211. 0
  212. );
  213. if (EFI_ERROR(Status)) {
  214. Print(L"cp: could not open/create %hs\n", Src->FullName);
  215. goto Done;
  216. }
  217. }
  218. Size = COPY_SIZE;
  219. Status = Src->Handle->GetInfo(Src->Handle, &GenericFileInfo, &Size, Info);
  220. if (EFI_ERROR(Status)) {
  221. Print(L"cp: can not get info of %hs\n", Src->FullName);
  222. goto Done;
  223. }
  224. SrcAttr = Info->Attribute;
  225. /*
  226. * If the dest file is not open, open/create it
  227. */
  228. if (!Dst->Handle) {
  229. if (SrcAttr & EFI_FILE_DIRECTORY) {
  230. CreateSubDir = TRUE;
  231. }
  232. Status = Dst->Parent->Open (
  233. Dst->Parent,
  234. &Dst->Handle,
  235. Dst->FileName,
  236. EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE,
  237. CreateSubDir ? EFI_FILE_DIRECTORY : 0
  238. );
  239. if (EFI_ERROR(Status)) {
  240. Print(L"cp: could not open/create %hs: %r\n", Dst->FullName, Status);
  241. goto Done;
  242. }
  243. if (CreateSubDir) {
  244. Print(L"mkdir %s\n", Dst->FullName);
  245. }
  246. }
  247. Size = COPY_SIZE;
  248. Status = Dst->Handle->GetInfo(Dst->Handle, &GenericFileInfo, &Size, Info);
  249. if (EFI_ERROR(Status)) {
  250. Print(L"cp: can not get info of %hs\n", Dst->FullName);
  251. goto Done;
  252. }
  253. DstAttr = Info->Attribute;
  254. /*
  255. * If the source is a file, but the dest is a directory we need to create a sub-file
  256. */
  257. if (!(SrcAttr & EFI_FILE_DIRECTORY) && (DstAttr & EFI_FILE_DIRECTORY)) {
  258. Dst = CpCreateChild (Dst, Src->FileName, &Cleanup);
  259. CopyCP (Src, Dst, FALSE);
  260. goto Done;
  261. }
  262. /*
  263. * Copy the source
  264. */
  265. if (!(SrcAttr & EFI_FILE_DIRECTORY)) {
  266. /*
  267. * Copy the file's contents
  268. */
  269. Print(L"%s -> %s ", Src->FullName, Dst->FullName);
  270. Src->Handle->SetPosition (Src->Handle, 0);
  271. Dst->Handle->SetPosition (Dst->Handle, 0);
  272. /*
  273. * Set the size of the destination file to 0.
  274. */
  275. Status = Dst->Handle->GetInfo(Dst->Handle, &GenericFileInfo, &Size, Info);
  276. if (!EFI_ERROR(Status)) {
  277. Info->FileSize = 0;
  278. Status = Dst->Handle->SetInfo(
  279. Dst->Handle,
  280. &GenericFileInfo,
  281. (UINTN) Info->Size,
  282. Info
  283. );
  284. }
  285. for (; ;) {
  286. Size = COPY_SIZE;
  287. Status = Src->Handle->Read (Src->Handle, &Size, CpBuffer);
  288. if (!Size) {
  289. break;
  290. }
  291. if (EFI_ERROR(Status)) {
  292. Print(L"- read error: %r\n", Status);
  293. break;
  294. }
  295. WriteSize = Size;
  296. Status = Dst->Handle->Write (Dst->Handle, &WriteSize, CpBuffer);
  297. if (EFI_ERROR(Status)) {
  298. Print(L"- write error: %r\n", Status);
  299. break;
  300. }
  301. if (WriteSize != Size) {
  302. Print(L"- short write\n");
  303. break;
  304. }
  305. }
  306. if (Size) {
  307. Dst->Handle->Delete (Dst->Handle);
  308. Dst->Handle = NULL;
  309. goto Done;
  310. }
  311. Print(L"[ok]\n");
  312. } else {
  313. /*
  314. * Copy all the sub-entries
  315. */
  316. Src->Handle->SetPosition (Src->Handle, 0);
  317. for (; ;) {
  318. Size = COPY_SIZE;
  319. Status = Src->Handle->Read (Src->Handle, &Size, CpBuffer);
  320. if (EFI_ERROR(Status) || Size == 0) {
  321. break;
  322. }
  323. /*
  324. * Skip "." and ".."
  325. */
  326. if (StriCmp(Info->FileName, L".") == 0 ||
  327. StriCmp(Info->FileName, L"..") == 0) {
  328. continue;
  329. }
  330. /*
  331. * Copy the sub file
  332. */
  333. NewSrc = CpCreateChild (Src, Info->FileName, &Cleanup);
  334. NewDst = CpCreateChild (Dst, Info->FileName, &Cleanup);
  335. CopyCP (NewSrc, NewDst, FALSE);
  336. /*
  337. * Close the handles
  338. */
  339. ShellFreeFileList (&Cleanup);
  340. /* next... */
  341. }
  342. }
  343. Done:
  344. ShellFreeFileList (&Cleanup);
  345. }