搜尋此網誌

2013年2月26日 星期二

fopen(),fclose(),fseek(),fwrite(),fread(),fgetc(),fput() --- EFI/UEFI實作


#define FILE EFI_LIST_ENTRY
#define MAX_FILE_LIST_POINT_BUFF_SIZE  256
FILE FileList_Buffer[MAX_FILE_LIST_POINT_BUFF_SIZE];
UINTN FileList_Count = 0;
/*************************************************************************/
FILE *fopen(const char *filename, const char *mode )
{
    FILE *ptr_file_list = &FileList_Buffer[FileList_Count];
    EFI_STATUS          Status;
    CHAR16                VarStr[256];
    CHAR16                ModeStr[256];

    EFI_LIST_ENTRY       *Link;
    SHELL_FILE_ARG      *Arg;
    UINTN                      Index;
    BOOLEAN                 IsSameFile;

    if (FileList_Count >= MAX_FILE_LIST_POINT_BUFF_SIZE)
        return NULL;

    ascii_str_to_unicode_str((CHAR8 *)mode, ModeStr);

    if ((strcmp (mode, "w") != 0) && (strcmp (mode, "a") != 0) && (strcmp (mode, "r") != 0)) {
        Print (L"=>No Supported this mode(%s)\n", ModeStr);
        return NULL;
    }

    InitializeListHead (ptr_file_list);

    ascii_str_to_unicode_str((CHAR8 *)filename, VarStr);

    Status = ShellFileMetaArg (VarStr, ptr_file_list);

    if (EFI_ERROR (Status) || IsListEmpty (ptr_file_list)) {
      Print (L"=>fopen error(%x)\n", Status);
      return NULL;
    }

    IsSameFile = FALSE;
    for (Link = ptr_file_list->Flink; Link != ptr_file_list && SI->RedirArgc; Link = Link->Flink) {
        BREAK_LOOP_ON_ESC ();
        Arg = CR (Link, SHELL_FILE_ARG, Link, SHELL_FILE_ARG_SIGNATURE);
        IsSameFile  = FALSE;
        for (Index = 1; Index < SI->RedirArgc; Index += 2) {
            if (!EFI_ERROR (LibCompareFile (Arg->FullName, SI->RedirArgv[Index], &IsSameFile)) && IsSameFile) {
                break;
            }
        }

        if (IsSameFile) {
            break;
        }
    }

    if (!IsSameFile) {
        for (Link = ptr_file_list->Flink; Link != ptr_file_list; Link = Link->Flink) {
            BREAK_LOOP_ON_ESC ();
            Arg = CR (Link, SHELL_FILE_ARG, Link, SHELL_FILE_ARG_SIGNATURE);
            if ((Arg->Status == EFI_NOT_FOUND) && ((strcmp (mode, "w") == 0) || (strcmp (mode, "a") == 0))) {
                    Status = Arg->Parent->Open (
                              Arg->Parent,
                              HiiHandle,
                              Arg->FileName,
                              EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE,
                              0 /*Directory:EFI_FILE_DIRECTORY or file:0*/
                              );
                    if (!EFI_ERROR (Status)) {
                        ShellFreeFileList (ptr_file_list);
                        Status = ShellFileMetaArg (VarStr, ptr_file_list);
                        if (EFI_ERROR (Status)) {
                            Print (L"=>Can't create the file(%s).\n", VarStr);
                            return NULL;
                        }
                    } else {
                        Print (L"=>Parent Can't create the file(%s).\n", Arg->FileName);
                        return NULL;
                    }

            } if ((Arg->Status == EFI_NOT_FOUND) && (strcmp (mode, "r") == 0)) {
                   ShellFreeFileList (ptr_file_list);
                   return NULL;
            }
        }
    } else {
        Status = EFI_REDIRECTION_SAME;
    }

    FileList_Count ++;

    return EFI_ERROR(Status) ? NULL : ptr_file_list;
}
/*************************************************************************/
int fclose(FILE *ptr_file_list)
{
    ShellFreeFileList (ptr_file_list);
    return 0;
}
/*************************************************************************/
long fseek( FILE *ptr_file_list, long offset, int where )
{
    EFI_STATUS             Status = EFI_SUCCESS;
    EFI_LIST_ENTRY       *Link;
    SHELL_FILE_ARG      *Arg;
    UINTN                      Index;
    BOOLEAN                 IsSameFile;
    UINT64                    CurrentPosition = 0;

    IsSameFile = FALSE;
    for (Link = ptr_file_list->Flink; Link != ptr_file_list && SI->RedirArgc; Link = Link->Flink) {
        BREAK_LOOP_ON_ESC ();
        Arg         = CR (Link, SHELL_FILE_ARG, Link, SHELL_FILE_ARG_SIGNATURE);
        IsSameFile  = FALSE;
        for (Index = 1; Index < SI->RedirArgc; Index += 2) {
            if (!EFI_ERROR (LibCompareFile (Arg->FullName, SI->RedirArgv[Index], &IsSameFile)) && IsSameFile) {
                break;
            }
        }

        if (IsSameFile) {
            break;
        }
    }

    if (!IsSameFile) {
        for (Link = ptr_file_list->Flink; Link != ptr_file_list; Link = Link->Flink) {
            BREAK_LOOP_ON_ESC ();
            Arg     = CR (Link, SHELL_FILE_ARG, Link, SHELL_FILE_ARG_SIGNATURE);
            Status = Arg->Status;
            if (!EFI_ERROR (Status)) {
                EFI_FILE_HANDLE Handle;
                Handle = Arg->Handle;

                switch(where) {
                    case SEEK_SET:
                        Handle->SetPosition (Handle, offset);
                        break;
                    case SEEK_CUR:
                        Handle->GetPosition (Handle, &CurrentPosition);
                        Handle->SetPosition (Handle, CurrentPosition + offset);
                        break;
                    case SEEK_END:
                        Handle->SetPosition (Handle, Arg->Info->FileSize - offset);
                        break;
                    default:
                        Status = EFI_INVALID_PARAMETER;
                        break;
                }
            }
        }
    } else {
        Status = EFI_REDIRECTION_SAME;
    }

    return (!EFI_ERROR (Status)) ? 0 : -1;
}
/*************************************************************************/
EFI_STATUS
test_WriteFile (
    SHELL_FILE_ARG  *Arg,
    const void *buf,
    UINTN Size
  )
{
  EFI_STATUS      Status;
  CHAR16          *Buffer = (CHAR16 *)buf;
  EFI_FILE_HANDLE Handle;

  Status = Arg->Status;

  if (!EFI_ERROR (Status) && (Size > 0)) {
    if (Arg->Info->Attribute & EFI_FILE_DIRECTORY) {
      Print (L"=>Write Attribute(%x)\n", Arg->Info->Attribute);
      return Status;
    }

    Handle = Arg->Handle;

    Status  = Handle->Write (Handle, &Size, Buffer);
    Status  = Handle->Flush (Handle);
  }
  return Status;
}

int fwrite(
    const void *buf,
    unsigned long elsize,
    unsigned long  nelem,
    FILE *ptr_file_list
) {
    EFI_STATUS             Status = EFI_SUCCESS;
    EFI_LIST_ENTRY       *Link;
    SHELL_FILE_ARG      *Arg;
    UINTN                      Index;
    BOOLEAN                 IsSameFile;
   
    IsSameFile = FALSE;
    for (Link = ptr_file_list->Flink; Link != ptr_file_list && SI->RedirArgc; Link = Link->Flink) {
        BREAK_LOOP_ON_ESC ();
        Arg         = CR (Link, SHELL_FILE_ARG, Link, SHELL_FILE_ARG_SIGNATURE);
        IsSameFile  = FALSE;
        for (Index = 1; Index < SI->RedirArgc; Index += 2) {
            if (!EFI_ERROR (LibCompareFile (Arg->FullName, SI->RedirArgv[Index], &IsSameFile)) && IsSameFile) {
                break;
            }
        }

        if (IsSameFile) {
            break;
        }
    }

    if (!IsSameFile) {
        for (Link = ptr_file_list->Flink; Link != ptr_file_list; Link = Link->Flink) {
            BREAK_LOOP_ON_ESC ();
            Arg     = CR (Link, SHELL_FILE_ARG, Link, SHELL_FILE_ARG_SIGNATURE);
            Status = test_WriteFile (Arg, buf, (UINTN)(elsize * nelem));
        }
    } else {
        Status = EFI_REDIRECTION_SAME;
    }

    return (!EFI_ERROR (Status)) ? 0 : -1;
}
/*************************************************************************/
EFI_STATUS
test_ReadFile (
    SHELL_FILE_ARG  *Arg,
    const void *buf,
    UINTN Size
  )
{
  EFI_STATUS      Status;
  CHAR16          *Buffer = (CHAR16 *)buf;
  EFI_FILE_HANDLE Handle;

  Status = Arg->Status;

  if (!EFI_ERROR (Status) && (Size > 0)) {
    if (Arg->Info->Attribute & EFI_FILE_DIRECTORY) {
      Print (L"=>Read Attribute(%x)\n", Arg->Info->Attribute);
      return Status;
    }

    Handle = Arg->Handle;

    Status  = Handle->Read (Handle, &Size, Buffer);
  }
  return Status;
}

int fread(
    const void *buf,
    unsigned long elsize,
    unsigned long  nelem,
    FILE *ptr_file_list
) {
    EFI_STATUS             Status = EFI_SUCCESS;
    EFI_LIST_ENTRY       *Link;
    SHELL_FILE_ARG      *Arg;
    UINTN                      Index;
    BOOLEAN                 IsSameFile;
   
    IsSameFile = FALSE;
    for (Link = ptr_file_list->Flink; Link != ptr_file_list && SI->RedirArgc; Link = Link->Flink) {
        BREAK_LOOP_ON_ESC ();
        Arg         = CR (Link, SHELL_FILE_ARG, Link, SHELL_FILE_ARG_SIGNATURE);
        IsSameFile  = FALSE;
        for (Index = 1; Index < SI->RedirArgc; Index += 2) {
            if (!EFI_ERROR (LibCompareFile (Arg->FullName, SI->RedirArgv[Index], &IsSameFile)) && IsSameFile) {
                break;
            }
        }

        if (IsSameFile) {
            break;
        }
    }

    if (!IsSameFile) {
        for (Link = ptr_file_list->Flink; Link != ptr_file_list; Link = Link->Flink) {
            BREAK_LOOP_ON_ESC ();
            Arg     = CR (Link, SHELL_FILE_ARG, Link, SHELL_FILE_ARG_SIGNATURE);
            Status = test_ReadFile (Arg, buf, (UINTN)(elsize * nelem));
        }
    } else {
        Status = EFI_REDIRECTION_SAME;
    }

    return (!EFI_ERROR (Status)) ? 0 : -1;
}
/*************************************************************************/
long ftell(FILE *ptr_file_list)
{
    EFI_STATUS             Status = EFI_SUCCESS;
    EFI_LIST_ENTRY       *Link;
    SHELL_FILE_ARG      *Arg;
    UINTN                      Index;
    BOOLEAN                 IsSameFile;
    UINTN                      FileSize = 0;

    IsSameFile = FALSE;
    for (Link = ptr_file_list->Flink; Link != ptr_file_list && SI->RedirArgc; Link = Link->Flink) {
        BREAK_LOOP_ON_ESC ();
        Arg         = CR (Link, SHELL_FILE_ARG, Link, SHELL_FILE_ARG_SIGNATURE);
        IsSameFile  = FALSE;
        for (Index = 1; Index < SI->RedirArgc; Index += 2) {
            if (!EFI_ERROR (LibCompareFile (Arg->FullName, SI->RedirArgv[Index], &IsSameFile)) && IsSameFile) {
                break;
            }
        }

        if (IsSameFile) {
            break;
        }
    }

    if (!IsSameFile) {
        for (Link = ptr_file_list->Flink; Link != ptr_file_list; Link = Link->Flink) {
            BREAK_LOOP_ON_ESC ();
            Arg     = CR (Link, SHELL_FILE_ARG, Link, SHELL_FILE_ARG_SIGNATURE);
            Status = Arg->Status;
            if (!EFI_ERROR (Status)) {
                FileSize  = (UINTN) Arg->Info->FileSize;
            }
        }
    } else {
        Status = EFI_REDIRECTION_SAME;
    }

    return (long)FileSize;
}
/*************************************************************************/

int fputc(
    int c,
    FILE *ptr_file_list
) {
    EFI_STATUS             Status = EFI_SUCCESS;
    EFI_LIST_ENTRY       *Link;
    SHELL_FILE_ARG      *Arg;
    UINTN                      Index;
    BOOLEAN                 IsSameFile;

    //
    // Expand each arg and type each file
    //
    IsSameFile = FALSE;
    for (Link = ptr_file_list->Flink; Link != ptr_file_list && SI->RedirArgc; Link = Link->Flink) {
        BREAK_LOOP_ON_ESC ();
        Arg         = CR (Link, SHELL_FILE_ARG, Link, SHELL_FILE_ARG_SIGNATURE);
        IsSameFile  = FALSE;
        for (Index = 1; Index < SI->RedirArgc; Index += 2) {
            if (!EFI_ERROR (LibCompareFile (Arg->FullName, SI->RedirArgv[Index], &IsSameFile)) && IsSameFile) {
                break;
            }
        }

        if (IsSameFile) {
            break;
        }
    }

    if (!IsSameFile) {
        for (Link = ptr_file_list->Flink; Link != ptr_file_list; Link = Link->Flink) {
            BREAK_LOOP_ON_ESC ();
            Arg     = CR (Link, SHELL_FILE_ARG, Link, SHELL_FILE_ARG_SIGNATURE);
            Status = MV_WriteFile (Arg, (void *)&c, (UINTN)1);
        }
    } else {
        Status = EFI_REDIRECTION_SAME;
    }

    return (!EFI_ERROR (Status)) ? 0 : -1;
}
/*************************************************************************/
int fgetc(
    FILE *ptr_file_list
) {
    EFI_STATUS             Status = EFI_SUCCESS;
    EFI_LIST_ENTRY       *Link;
    SHELL_FILE_ARG      *Arg;
    UINTN                      Index;
    BOOLEAN                 IsSameFile;
    int c = -1;
    
    //
    // Expand each arg and type each file
    //
    IsSameFile = FALSE;
    for (Link = ptr_file_list->Flink; Link != ptr_file_list && SI->RedirArgc; Link = Link->Flink) {
        BREAK_LOOP_ON_ESC ();
        Arg         = CR (Link, SHELL_FILE_ARG, Link, SHELL_FILE_ARG_SIGNATURE);
        IsSameFile  = FALSE;
        for (Index = 1; Index < SI->RedirArgc; Index += 2) {
            if (!EFI_ERROR (LibCompareFile (Arg->FullName, SI->RedirArgv[Index], &IsSameFile)) && IsSameFile) {
                break;
            }
        }

        if (IsSameFile) {
            break;
        }
    }

    if (!IsSameFile) {
        for (Link = ptr_file_list->Flink; Link != ptr_file_list; Link = Link->Flink) {
            BREAK_LOOP_ON_ESC ();
            Arg     = CR (Link, SHELL_FILE_ARG, Link, SHELL_FILE_ARG_SIGNATURE);
            Status = MV_ReadFile (Arg, (void *)&c, (UINTN)1);
        }
    } else {
        Status = EFI_REDIRECTION_SAME;
    }

    return (!EFI_ERROR (Status)) ? c : -1;
}
/*************************************************************************/

沒有留言:

張貼留言