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.

574 lines
12 KiB

  1. /*++
  2. Copyright (c) 1998 Intel Corporation
  3. Module Name:
  4. marg.c
  5. Abstract:
  6. Revision History
  7. --*/
  8. #include "shelle.h"
  9. /*
  10. *
  11. */
  12. typedef struct _CWD {
  13. struct _CWD *Next;
  14. CHAR16 Name[1];
  15. } SENV_CWD;
  16. CHAR16 *
  17. SEnvFileHandleToFileName (
  18. IN EFI_FILE_HANDLE Handle
  19. )
  20. {
  21. UINTN BufferSize, bs;
  22. SENV_CWD *CwdHead, *Cwd;
  23. POOL_PRINT Str;
  24. EFI_FILE_INFO *Info;
  25. EFI_STATUS Status;
  26. EFI_FILE_HANDLE NextDir;
  27. ASSERT_LOCKED(&SEnvLock);
  28. Status = EFI_SUCCESS;
  29. CwdHead = NULL;
  30. ZeroMem (&Str, sizeof(Str));
  31. /*
  32. *
  33. */
  34. Status = Handle->Open(Handle, &Handle, L".", EFI_FILE_MODE_READ, 0);
  35. if (EFI_ERROR(Status)) {
  36. Handle = NULL;
  37. goto Done;
  38. }
  39. BufferSize = SIZE_OF_EFI_FILE_INFO + 1024;
  40. Info = AllocatePool(BufferSize);
  41. if (!Info) {
  42. goto Done;
  43. }
  44. /*
  45. * Reverse out the current directory on the device
  46. */
  47. for (; ;) {
  48. bs = BufferSize;
  49. Status = Handle->GetInfo(Handle, &GenericFileInfo, &bs, Info);
  50. if (EFI_ERROR(Status)) {
  51. goto Done;
  52. }
  53. /*
  54. * Allocate & chain in a new name node
  55. */
  56. Cwd = AllocatePool (sizeof(SENV_CWD) + StrSize (Info->FileName));
  57. if (!Cwd) {
  58. goto Done;
  59. }
  60. StrCpy (Cwd->Name, Info->FileName);
  61. Cwd->Next = CwdHead;
  62. CwdHead = Cwd;
  63. /*
  64. * Move to the parent directory
  65. */
  66. Status = Handle->Open (Handle, &NextDir, L"..", EFI_FILE_MODE_READ, 0);
  67. if (EFI_ERROR(Status)) {
  68. break;
  69. }
  70. Handle->Close (Handle);
  71. Handle = NextDir;
  72. }
  73. /*
  74. * Build the name string of the current path
  75. */
  76. if (CwdHead->Next) {
  77. for (Cwd=CwdHead->Next; Cwd; Cwd=Cwd->Next) {
  78. CatPrint (&Str, L"\\%s", Cwd->Name);
  79. }
  80. } else {
  81. /* must be in the root */
  82. Str.str = StrDuplicate (L"\\");
  83. }
  84. Done:
  85. while (CwdHead) {
  86. Cwd = CwdHead;
  87. CwdHead = CwdHead->Next;
  88. FreePool (Cwd);
  89. }
  90. if (Info) {
  91. FreePool (Info);
  92. }
  93. if (Handle) {
  94. Handle->Close (Handle);
  95. }
  96. return Str.str;
  97. }
  98. VOID
  99. SEnvFreeFileArg (
  100. IN SHELL_FILE_ARG *Arg
  101. )
  102. {
  103. if (Arg->Parent) {
  104. Arg->Parent->Close (Arg->Parent);
  105. }
  106. if (Arg->ParentName) {
  107. FreePool (Arg->ParentName);
  108. }
  109. if (Arg->ParentDevicePath) {
  110. FreePool (Arg->ParentDevicePath);
  111. }
  112. if (Arg->FullName) {
  113. FreePool (Arg->FullName);
  114. }
  115. if (Arg->FileName) {
  116. FreePool (Arg->FileName);
  117. }
  118. if (Arg->Handle) {
  119. Arg->Handle->Close (Arg->Handle);
  120. }
  121. if (Arg->Info) {
  122. FreePool (Arg->Info);
  123. }
  124. if (Arg->Link.Flink) {
  125. RemoveEntryList (&Arg->Link);
  126. }
  127. FreePool(Arg);
  128. }
  129. EFI_STATUS
  130. SEnvFreeFileList (
  131. IN OUT LIST_ENTRY *ListHead
  132. )
  133. {
  134. SHELL_FILE_ARG *Arg;
  135. while (!IsListEmpty(ListHead)) {
  136. Arg = CR(ListHead->Flink, SHELL_FILE_ARG, Link, SHELL_FILE_ARG_SIGNATURE);
  137. SEnvFreeFileArg (Arg);
  138. }
  139. return EFI_SUCCESS;
  140. }
  141. SHELL_FILE_ARG *
  142. SEnvNewFileArg (
  143. IN EFI_FILE_HANDLE Parent,
  144. IN UINT64 OpenMode,
  145. IN EFI_DEVICE_PATH *ParentPath,
  146. IN CHAR16 *ParentName,
  147. IN CHAR16 *FileName
  148. )
  149. {
  150. SHELL_FILE_ARG *Arg;
  151. CHAR16 *LPath, *p;
  152. UINTN Len;
  153. Arg = NULL;
  154. /*
  155. * Allocate a new arg structure
  156. */
  157. Arg = AllocateZeroPool (sizeof(SHELL_FILE_ARG));
  158. if (!Arg) {
  159. goto Done;
  160. }
  161. Arg->Signature = SHELL_FILE_ARG_SIGNATURE;
  162. Parent->Open (Parent, &Arg->Parent, L".", OpenMode, 0);
  163. Arg->ParentDevicePath = DuplicateDevicePath (ParentPath);
  164. Arg->ParentName = StrDuplicate(ParentName);
  165. if (!Arg->Parent || !Arg->ParentDevicePath || !Arg->ParentName) {
  166. Arg->Status = EFI_OUT_OF_RESOURCES;
  167. goto Done;
  168. }
  169. /*
  170. * Open the target file
  171. */
  172. Arg->Status = Parent->Open(
  173. Parent,
  174. &Arg->Handle,
  175. FileName,
  176. OpenMode,
  177. 0
  178. );
  179. if (Arg->Status == EFI_WRITE_PROTECTED) {
  180. OpenMode = OpenMode & ~EFI_FILE_MODE_WRITE;
  181. Arg->Status = Parent->Open (
  182. Parent,
  183. &Arg->Handle,
  184. FileName,
  185. OpenMode,
  186. 0
  187. );
  188. }
  189. Arg->OpenMode = OpenMode;
  190. if (Arg->Handle) {
  191. Arg->Info = LibFileInfo(Arg->Handle);
  192. }
  193. /*
  194. * Compute the file's full name
  195. */
  196. Arg->FileName = StrDuplicate(FileName);
  197. if (StriCmp (FileName, L".") == 0) {
  198. /* it is the same as the parent */
  199. Arg->FullName = StrDuplicate(Arg->ParentName);
  200. } else if (StriCmp(FileName, L"..") == 0) {
  201. LPath = NULL;
  202. for (p=Arg->ParentName; *p; p++) {
  203. if (*p == L'\\') {
  204. LPath = p;
  205. }
  206. }
  207. if (LPath) {
  208. Arg->FullName = PoolPrint(L"%.*s", (UINTN) (LPath - Arg->ParentName), Arg->ParentName);
  209. }
  210. }
  211. if (!Arg->FullName) {
  212. /* append filename to parent's name to get the file's full name */
  213. Len = StrLen(Arg->ParentName);
  214. if (Len && Arg->ParentName[Len-1] == '\\') {
  215. Len -= 1;
  216. }
  217. if (FileName[0] == '\\') {
  218. FileName += 1;
  219. }
  220. Arg->FullName = PoolPrint(L"%.*s\\%s", Len, Arg->ParentName, FileName);
  221. }
  222. if (!Arg->FileName || !Arg->FileName) {
  223. Arg->Status = EFI_OUT_OF_RESOURCES;
  224. }
  225. Done:
  226. if (Arg && Arg->Status == EFI_OUT_OF_RESOURCES) {
  227. SEnvFreeFileArg (Arg);
  228. Arg = NULL;
  229. }
  230. if (Arg && !EFI_ERROR(Arg->Status) && !Arg->Handle) {
  231. Arg->Status = EFI_NOT_FOUND;
  232. }
  233. return Arg;
  234. }
  235. EFI_STATUS
  236. SEnvFileMetaArg (
  237. IN CHAR16 *Path,
  238. IN OUT LIST_ENTRY *ListHead
  239. )
  240. {
  241. VARIABLE_ID *Var;
  242. EFI_STATUS Status;
  243. EFI_DEVICE_PATH *RPath, *TPath;
  244. EFI_DEVICE_PATH *ParentPath;
  245. FILEPATH_DEVICE_PATH *FilePath;
  246. EFI_FILE_INFO *Info;
  247. UINTN bs, BufferSize;
  248. EFI_FILE_HANDLE Parent;
  249. SHELL_FILE_ARG *Arg;
  250. CHAR16 *ParentName;
  251. CHAR16 *LPath, *p;
  252. UINT64 OpenMode;
  253. BOOLEAN Found;
  254. RPath = NULL;
  255. Parent = NULL;
  256. ParentPath = NULL;
  257. ParentName = NULL;
  258. AcquireLock (&SEnvLock);
  259. BufferSize = SIZE_OF_EFI_FILE_INFO + 1024;
  260. Info = AllocatePool (BufferSize);
  261. if (!Info) {
  262. Status = EFI_OUT_OF_RESOURCES;
  263. goto Done;
  264. }
  265. /*
  266. * Get the device
  267. */
  268. Var = SEnvMapDeviceFromName (&Path);
  269. if (!Var) {
  270. Arg = AllocateZeroPool (sizeof(SHELL_FILE_ARG));
  271. Arg->Signature = SHELL_FILE_ARG_SIGNATURE;
  272. Arg->Status = EFI_NO_MAPPING;
  273. Arg->ParentName = StrDuplicate(Path);
  274. Arg->FullName = StrDuplicate(Path);
  275. Arg->FileName = StrDuplicate(Path);
  276. InsertTailList (ListHead, &Arg->Link);
  277. Status = EFI_SUCCESS;
  278. goto Done;
  279. }
  280. ParentPath = DuplicateDevicePath ((EFI_DEVICE_PATH *) Var->u.Value);
  281. /*
  282. * If the path is realitve, append the current dir of the device to the dpath
  283. */
  284. if (*Path != '\\') {
  285. RPath = SEnvIFileNameToPath (Var->CurDir ? Var->CurDir : L"\\");
  286. TPath = AppendDevicePath (ParentPath, RPath);
  287. if (!RPath || !TPath) {
  288. Status = EFI_OUT_OF_RESOURCES;
  289. goto Done;
  290. }
  291. FreePool (ParentPath);
  292. FreePool (RPath);
  293. RPath = NULL;
  294. ParentPath = TPath;
  295. }
  296. /*
  297. * If there is a path before the last node of the name, then
  298. * append it and strip path to the last node.
  299. */
  300. LPath = NULL;
  301. for(p=Path; *p; p++) {
  302. if (*p == '\\') {
  303. LPath = p;
  304. }
  305. }
  306. if (LPath) {
  307. *LPath = 0;
  308. RPath = SEnvIFileNameToPath(Path);
  309. TPath = AppendDevicePath (ParentPath, RPath);
  310. if (!RPath || !TPath) {
  311. Status = EFI_OUT_OF_RESOURCES;
  312. goto Done;
  313. }
  314. FreePool (ParentPath);
  315. FreePool (RPath);
  316. RPath = NULL;
  317. ParentPath = TPath;
  318. Path = LPath + 1;
  319. }
  320. /*
  321. * Open the parent dir
  322. */
  323. OpenMode = EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE;
  324. Parent = ShellOpenFilePath(ParentPath, OpenMode);
  325. if (!Parent) {
  326. OpenMode = EFI_FILE_MODE_READ;
  327. Parent = ShellOpenFilePath(ParentPath, OpenMode);
  328. }
  329. if (Parent) {
  330. p = SEnvFileHandleToFileName(Parent);
  331. if (p) {
  332. ParentName = PoolPrint(L"%s:%s", Var->Name, p);
  333. FreePool (p);
  334. }
  335. }
  336. if (!Parent) {
  337. Status = EFI_NOT_FOUND;
  338. goto Done;
  339. }
  340. bs = BufferSize;
  341. Status = Parent->GetInfo(Parent, &GenericFileInfo, &bs, Info);
  342. if (EFI_ERROR(Status)) {
  343. goto Done;
  344. }
  345. /*
  346. * Parent - file handle to parent directory
  347. * ParentPath - device path of parent dir
  348. * ParentName - name string of parent directory
  349. * ParentGuid - last guid of parent path
  350. *
  351. * Path - remaining node name
  352. */
  353. /*
  354. * BUGBUG: if the name doesn't have any meta chars,
  355. * then just open the one file
  356. */
  357. Found = FALSE;
  358. for (p=Path; *p && !Found; p++) {
  359. /* BUGBUG: need to handle '^' */
  360. switch (*p) {
  361. case '*':
  362. case '[':
  363. case '?':
  364. Found = TRUE;
  365. break;
  366. }
  367. }
  368. if (!Found) {
  369. TPath = SEnvIFileNameToPath (Path);
  370. ASSERT (DevicePathType(TPath) == MEDIA_DEVICE_PATH && DevicePathSubType(TPath) == MEDIA_FILEPATH_DP);
  371. FilePath = (FILEPATH_DEVICE_PATH *) TPath;
  372. Arg = SEnvNewFileArg(Parent, OpenMode, ParentPath, ParentName, FilePath->PathName);
  373. FreePool (TPath);
  374. if (!Arg) {
  375. Status = EFI_OUT_OF_RESOURCES;
  376. goto Done;
  377. }
  378. InsertTailList (ListHead, &Arg->Link);
  379. } else {
  380. /*
  381. * Check all the files for matches
  382. */
  383. Parent->SetPosition (Parent, 0);
  384. Found = FALSE;
  385. for (; ;) {
  386. /*
  387. * Read each file entry
  388. */
  389. bs = BufferSize;
  390. Status = Parent->Read (Parent, &bs, Info);
  391. if (EFI_ERROR(Status) || bs == 0) {
  392. break;
  393. }
  394. /*
  395. * Skip "." and ".."
  396. */
  397. if (StriCmp(Info->FileName, L".") == 0 ||
  398. StriCmp(Info->FileName, L"..") == 0) {
  399. continue;
  400. }
  401. /*
  402. * See if this one matches
  403. */
  404. if (!MetaiMatch(Info->FileName, Path)) {
  405. continue;
  406. }
  407. Found = TRUE;
  408. Arg = SEnvNewFileArg(Parent, OpenMode, ParentPath, ParentName, Info->FileName);
  409. if (!Arg) {
  410. Status = EFI_OUT_OF_RESOURCES;
  411. goto Done;
  412. }
  413. InsertTailList (ListHead, &Arg->Link);
  414. /* check next file entry */
  415. }
  416. /*
  417. * If no match was found, then add a not-found entry for this name
  418. */
  419. if (!Found) {
  420. Arg = SEnvNewFileArg(Parent, OpenMode, ParentPath, ParentName, Path);
  421. if (!Arg) {
  422. Status = EFI_OUT_OF_RESOURCES;
  423. goto Done;
  424. }
  425. Arg->Status = EFI_NOT_FOUND;
  426. InsertTailList (ListHead, &Arg->Link);
  427. }
  428. }
  429. /*
  430. * Done
  431. */
  432. Done:
  433. ReleaseLock (&SEnvLock);
  434. if (Parent) {
  435. Parent->Close (Parent);
  436. }
  437. if (RPath) {
  438. FreePool (RPath);
  439. }
  440. if (ParentPath) {
  441. FreePool (ParentPath);
  442. }
  443. if (ParentName) {
  444. FreePool (ParentName);
  445. }
  446. if (Info) {
  447. FreePool (Info);
  448. }
  449. return Status;
  450. }