/**
  Function for 'cd' command.

  @param[in] ImageHandle  Handle to the Image (NULL if Internal).
  @param[in] SystemTable  Pointer to the System Table (NULL if Internal).
**/
SHELL_STATUS
EFIAPI
ShellCommandRunCd (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{
  EFI_STATUS        Status;
  LIST_ENTRY        *Package;
  CONST CHAR16      *Cwd;
  CHAR16            *Path;
  CHAR16            *Drive;
  CHAR16            *ProblemParam;
  SHELL_STATUS      ShellStatus;
  CONST CHAR16      *Param1;
  CHAR16            *Param1Copy;
  CHAR16            *Walker;
  CHAR16            *Splitter;
  CHAR16            *TempBuffer;
  UINTN             TotalSize;

  ProblemParam  = NULL;
  ShellStatus   = SHELL_SUCCESS;
  Cwd           = NULL;
  Path          = NULL;
  Drive         = NULL;
  Splitter      = NULL;
  TempBuffer    = NULL;
  TotalSize     = 0;

  Status = CommandInit();
  ASSERT_EFI_ERROR(Status);

  //
  // initialize the shell lib (we must be in non-auto-init...)
  //
  Status = ShellInitialize();
  ASSERT_EFI_ERROR(Status);

  //
  // parse the command line
  //
  Status = ShellCommandLineParse (EmptyParamList, &Package, &ProblemParam, TRUE);
  if (EFI_ERROR(Status)) {
    if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {
      ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"cd", ProblemParam);  
      FreePool(ProblemParam);
      ShellStatus = SHELL_INVALID_PARAMETER;
    } else {
      ASSERT(FALSE);
    }
  }

  //
  // check for "-?"
  //
  if (ShellCommandLineGetFlag(Package, L"-?")) {
    ASSERT(FALSE);
  } else if (ShellCommandLineGetRawValue(Package, 2) != NULL) {
    ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel2HiiHandle, L"cd");  
    ShellStatus = SHELL_INVALID_PARAMETER;
  } else {
    //
    // remember that param 0 is the command name
    // If there are 0 value parameters, then print the current directory
    // else If there are 2 value parameters, then print the error message
    // else If there is  1 value paramerer , then change the directory
    //
    Cwd = ShellGetCurrentDir (NULL);

    // 第一步,获得当前工作路目录。
    // 此时cwd 为fs0:
    if (Cwd == NULL) {
      ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN(STR_GEN_NO_CWD), gShellLevel2HiiHandle, L"cd");
      ShellStatus = SHELL_NOT_FOUND;
    } else {
      // Param1 即为要进入的目录文件夹
      Param1 = ShellCommandLineGetRawValue (Package, 1);
      if (Param1 == NULL) {
        //
        // display the current directory
        //
        ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN(STR_CD_PRINT), gShellLevel2HiiHandle, Cwd);
      } else {
        Param1Copy = CatSPrint (NULL, L"%s", Param1, NULL);
        for (Walker = Param1Copy; Walker != NULL && *Walker != CHAR_NULL; Walker++) {
          if (*Walker == L'\"') {
            CopyMem (Walker, Walker + 1, StrSize(Walker) - sizeof(Walker[0]));
          }
        }
        // Walker 即为目录文件夹到 \
        if (Param1Copy != NULL && IsCurrentFileSystem (Param1Copy, Cwd)) {

          // 
          Status = ReplaceDriveWithCwd (&Param1Copy,Cwd);
          if (!EFI_ERROR (Status)) {
            Param1Copy = PathCleanUpDirectories (Param1Copy);
          }
        } else {
          //
          // Can't use cd command to change filesystem.
          //
          ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_CD_NF), gShellLevel2HiiHandle, L"cd");
          Status = EFI_NOT_FOUND;
        }

        if (!EFI_ERROR(Status) && Param1Copy != NULL) {
          Splitter = StrStr (Cwd, L":");
          if (Param1Copy[0] == L'\\') {
            //
            // Absolute Path on current drive letter.
            //
            TotalSize = ((Splitter - Cwd + 1) * sizeof(CHAR16)) + StrSize(Param1Copy);
            TempBuffer = AllocateZeroPool (TotalSize);
            if (TempBuffer == NULL) {
              Status = EFI_OUT_OF_RESOURCES;
            } else {
              StrnCpyS (TempBuffer, TotalSize / sizeof(CHAR16), Cwd, (Splitter - Cwd + 1));
              StrCatS (TempBuffer, TotalSize / sizeof(CHAR16), Param1Copy);

              FreePool (Param1Copy);
              Param1Copy = TempBuffer;
              TempBuffer = NULL;
            }
          } else {
            if (StrStr (Param1Copy,L":") == NULL) {
              TotalSize = StrSize (Cwd) + StrSize (Param1Copy);
              TempBuffer = AllocateZeroPool (TotalSize);
              if (TempBuffer == NULL) {
                Status = EFI_OUT_OF_RESOURCES;
              } else {
                StrCpyS (TempBuffer, TotalSize / sizeof (CHAR16), Cwd);
                StrCatS (TempBuffer, TotalSize / sizeof (CHAR16), L"\\");
                StrCatS (TempBuffer, TotalSize / sizeof (CHAR16), Param1Copy);

                FreePool (Param1Copy);
                Param1Copy = PathCleanUpDirectories (TempBuffer);
              }
            }
          }
        }

        if (!EFI_ERROR(Status)) {
          Status = ExtractDriveAndPath (Param1Copy, &Drive, &Path);
        }

        if (!EFI_ERROR (Status) && Drive != NULL && Path != NULL) {
          if (EFI_ERROR(ShellIsDirectory (Param1Copy))) {
            ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN(STR_GEN_NOT_DIR), gShellLevel2HiiHandle, L"cd", Param1Copy);
            ShellStatus = SHELL_NOT_FOUND;
          } else {

            // 这里调用的是 ShellProtocol.c 的 EfiShellSetCurDir (line 3031)
            Status = gEfiShellProtocol->SetCurDir (Drive, Path + 1);
            if (EFI_ERROR (Status)) {
              ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN(STR_GEN_DIR_NF), gShellLevel2HiiHandle, L"cd", Param1Copy);
              ShellStatus = SHELL_NOT_FOUND;
            }
          }
        }

        if (Drive != NULL) {
          FreePool (Drive);
        }

        if (Path != NULL) {
          FreePool (Path);
        }

        FreePool (Param1Copy);
      }
    }
  }


核心函数:

/**
  Changes the current directory on the specified device.

  If the FileSystem is NULL, and the directory Dir does not contain a file system's
  mapped name, this function changes the current working directory.

  If the FileSystem is NULL and the directory Dir contains a mapped name, then the
  current file system and the current directory on that file system are changed.

  If FileSystem is NULL, and Dir is not NULL, then this changes the current working file
  system.

  If FileSystem is not NULL and Dir is not NULL, then this function changes the current
  directory on the specified file system.

  If the current working directory or the current working file system is changed then the
  %cwd% environment variable will be updated

  Note that the current directory string should exclude the tailing backslash character.

  @param FileSystem             A pointer to the file system's mapped name. If NULL, then the current working
                                directory is changed.
  @param Dir                    Points to the NULL-terminated directory on the device specified by FileSystem.

  @retval EFI_SUCCESS           The operation was sucessful
  @retval EFI_NOT_FOUND         The file system could not be found
**/
EFI_STATUS
EFIAPI
EfiShellSetCurDir(
  IN CONST CHAR16 *FileSystem OPTIONAL,
  IN CONST CHAR16 *Dir
  )
{
  CHAR16          *MapName;
  SHELL_MAP_LIST  *MapListItem;
  UINTN           Size;
  EFI_STATUS      Status;
  CHAR16          *TempString;
  CHAR16          *DirectoryName;
  UINTN           TempLen;

  Size          = 0;
  MapName       = NULL;
  MapListItem   = NULL;
  TempString    = NULL;
  DirectoryName = NULL;

  if ((FileSystem == NULL && Dir == NULL) || Dir == NULL) {
    return (EFI_INVALID_PARAMETER);
  }

  if (IsListEmpty(&gShellMapList.Link)){
    return (EFI_NOT_FOUND);
  }
   // 毫无疑问, DirectoryName 就是我们的目录文件夹
  DirectoryName = StrnCatGrow(&DirectoryName, NULL, Dir, 0);
  ASSERT(DirectoryName != NULL);

  PathCleanUpDirectories(DirectoryName);

  if (FileSystem == NULL) {
    //
    // determine the file system mapping to use
    //
    if (StrStr(DirectoryName, L":") != NULL) {
      ASSERT(MapName == NULL);
      MapName = StrnCatGrow(&MapName, NULL, DirectoryName, (StrStr(DirectoryName, L":")-DirectoryName+1));
    }
    //
    // find the file system mapping's entry in the list
    // or use current
    //
    if (MapName != NULL) {
      MapListItem = ShellCommandFindMapItem(MapName);

      //
      // make that the current file system mapping
      //
      if (MapListItem != NULL) {
        gShellCurDir = MapListItem;
      }
    } else {
      MapListItem = gShellCurDir;
    }

    if (MapListItem == NULL) {
      FreePool (DirectoryName);
      SHELL_FREE_NON_NULL(MapName);
      return (EFI_NOT_FOUND);
    }

    //
    // now update the MapListItem's current directory
    //
    if (MapListItem->CurrentDirectoryPath != NULL && DirectoryName[StrLen(DirectoryName) - 1] != L':') {
      FreePool(MapListItem->CurrentDirectoryPath);
      MapListItem->CurrentDirectoryPath = NULL;
    }
    if (MapName != NULL) {
      TempLen = StrLen(MapName);
      if (TempLen != StrLen(DirectoryName)) {
        ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));
        MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, DirectoryName+StrLen(MapName), 0);
      }
      FreePool (MapName);
    } else {
      ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));
      MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, DirectoryName, 0);
    }
    if ((MapListItem->CurrentDirectoryPath != NULL && MapListItem->CurrentDirectoryPath[StrLen(MapListItem->CurrentDirectoryPath)-1] == L'\\') || (MapListItem->CurrentDirectoryPath == NULL)) {
      ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));
      if (MapListItem->CurrentDirectoryPath != NULL) {
        MapListItem->CurrentDirectoryPath[StrLen(MapListItem->CurrentDirectoryPath)-1] = CHAR_NULL;
    }
    }
  } else {
    //
    // cant have a mapping in the directory...
    //
    if (StrStr(DirectoryName, L":") != NULL) {
      FreePool (DirectoryName);
      return (EFI_INVALID_PARAMETER);
    }
    //
    // FileSystem != NULL
    //
    MapListItem = ShellCommandFindMapItem(FileSystem);
    if (MapListItem == NULL) {
      FreePool (DirectoryName);
      return (EFI_INVALID_PARAMETER);
    }
//    gShellCurDir = MapListItem;
    if (DirectoryName != NULL) {
      //
      // change current dir on that file system
      //

      if (MapListItem->CurrentDirectoryPath != NULL) {
        FreePool(MapListItem->CurrentDirectoryPath);
        DEBUG_CODE(MapListItem->CurrentDirectoryPath = NULL;);
      }
//      ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));
//      MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, FileSystem, 0);
      ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));
      MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, L"\\", 0);
      ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));
      MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, DirectoryName, 0);
      if (MapListItem->CurrentDirectoryPath != NULL && MapListItem->CurrentDirectoryPath[StrLen(MapListItem->CurrentDirectoryPath)-1] == L'\\') {
        ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));
        MapListItem->CurrentDirectoryPath[StrLen(MapListItem->CurrentDirectoryPath)-1] = CHAR_NULL;
      }
    }
  }
  FreePool (DirectoryName);

  // 结束之后,顺便更新一下环境变量
  //
  // if updated the current directory then update the environment variable
  //
  if (MapListItem == gShellCurDir) {
    Size = 0;
    ASSERT((TempString == NULL && Size == 0) || (TempString != NULL));
    StrnCatGrow(&TempString, &Size, MapListItem->MapName, 0);
    ASSERT((TempString == NULL && Size == 0) || (TempString != NULL));
    StrnCatGrow(&TempString, &Size, MapListItem->CurrentDirectoryPath, 0);
    Status =  InternalEfiShellSetEnv(L"cwd", TempString, TRUE);
    FreePool(TempString);
    return (Status);
  }
  return(EFI_SUCCESS);
}


Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐