コード例 #1
0
ファイル: file.c プロジェクト: tribals/efifs
/* GRUB uses a callback for each directory entry, whereas EFI uses repeated
 * firmware generated calls to FileReadDir() to get the info for each entry,
 * so we have to reconcile the twos. For now, we'll re-issue a call to GRUB
 * dir(), and run through all the entries (to find the one we
 * are interested in)  multiple times. Maybe later we'll try to optimize this
 * by building a one-off chained list of entries that we can parse...
 */
static INT32
DirHook(const CHAR8 *name, const GRUB_DIRHOOK_INFO *DirInfo, VOID *Data)
{
	EFI_STATUS Status;
	EFI_FILE_INFO *Info = (EFI_FILE_INFO *) Data;
	INT64 *Index = (INT64 *) &Info->FileSize;
	CHAR8 *filename = (CHAR8 *) Info->PhysicalSize;
	EFI_TIME Time = { 1970, 01, 01, 00, 00, 00, 0, 0, 0, 0, 0};

	// Eliminate '.' or '..'
	if ((name[0] ==  '.') && ((name[1] == 0) || ((name[1] == '.') && (name[2] == 0))))
		return 0;

	/* Ignore any entry that doesn't match our index */
	if ((*Index)-- != 0)
		return 0;

	strcpya(filename, name);

	Status = Utf8ToUtf16NoAlloc(filename, Info->FileName, (INTN)(Info->Size - sizeof(EFI_FILE_INFO)));
	if (EFI_ERROR(Status)) {
		if (Status != EFI_BUFFER_TOO_SMALL)
			PrintStatusError(Status, L"Could not convert directory entry to UTF-8");
		return (INT32) Status;
	}
	/* The Info struct size already accounts for the extra NUL */
	Info->Size = sizeof(*Info) + StrLen(Info->FileName) * sizeof(CHAR16);

	// Oh, and of course GRUB uses a 32 bit signed mtime value (seriously, wtf guys?!?)
	if (DirInfo->MtimeSet)
		GrubTimeToEfiTime(DirInfo->Mtime, &Time);
	CopyMem(&Info->CreateTime, &Time, sizeof(Time));
	CopyMem(&Info->LastAccessTime, &Time, sizeof(Time));
	CopyMem(&Info->ModificationTime, &Time, sizeof(Time));

	Info->Attribute = EFI_FILE_READ_ONLY;
	if (DirInfo->Dir)
		Info->Attribute |= EFI_FILE_DIRECTORY;

	return 0;
}
コード例 #2
0
ファイル: file.c プロジェクト: tribals/efifs
/**
 * Open file
 *
 * @v This			File handle
 * @ret new			New file handle
 * @v Name			File name
 * @v Mode			File mode
 * @v Attributes	File attributes (for newly-created files)
 * @ret Status		EFI status code
 */
static EFI_STATUS EFIAPI
FileOpen(EFI_FILE_HANDLE This, EFI_FILE_HANDLE *New,
		CHAR16 *Name, UINT64 Mode, UINT64 Attributes)
{
	EFI_STATUS Status;
	EFI_GRUB_FILE *File = _CR(This, EFI_GRUB_FILE, EfiFile);
	EFI_GRUB_FILE *NewFile;

	// TODO: Use dynamic buffers?
	char path[MAX_PATH], clean_path[MAX_PATH], *dirname;
	INTN i, len;
	BOOLEAN AbsolutePath = (*Name == L'\\');

	PrintInfo(L"Open(%llx%s, \"%s\")\n", (UINT64) This,
			IS_ROOT(File)?L" <ROOT>":L"", Name);

	/* Fail unless opening read-only */
	if (Mode != EFI_FILE_MODE_READ) {
		PrintWarning(L"File '%s' can only be opened in read-only mode\n", Name);
		return EFI_WRITE_PROTECTED;
	}

	/* Additional failures */
	if ((StrCmp(Name, L"..") == 0) && IS_ROOT(File)) {
		PrintInfo(L"Trying to open <ROOT>'s parent\n");
		return EFI_NOT_FOUND;
	}

	/* See if we're trying to reopen current (which the EFI Shell insists on doing) */
	if ((*Name == 0) || (StrCmp(Name, L".") == 0)) {
		PrintInfo(L"  Reopening %s\n", IS_ROOT(File)?L"<ROOT>":FileName(File));
		File->RefCount++;
		*New = This;
		PrintInfo(L"  RET: %llx\n", (UINT64) *New);
		return EFI_SUCCESS;
	}

	/* If we have an absolute path, don't bother completing with the parent */
	if (AbsolutePath) {
		len = 0;
	} else {
		strcpya(path, File->path);
		len = strlena(path);
		/* Add delimiter if needed */
		if ((len == 0) || (path[len-1] != '/'))
			path[len++] = '/';
	}

	/* Copy the rest of the path (converted to UTF-8) */
	Status = Utf16ToUtf8NoAlloc(Name, &path[len], sizeof(path) - len);
	if (EFI_ERROR(Status)) {
		PrintStatusError(Status, L"Could not convert path to UTF-8");
		return Status;
	}
	/* Convert the delimiters */
	for (i = strlena(path) - 1 ; i >= len; i--) {
		if (path[i] == '\\')
			path[i] = '/';
	}

	/* We only want to handle with absolute paths */
	clean_path[0] = '/';
	/* Find out if we're dealing with root by removing the junk */
	CopyPathRelative(&clean_path[1], path, MAX_PATH - 1);
	if (clean_path[1] == 0) {
		/* We're dealing with the root */
		PrintInfo(L"  Reopening <ROOT>\n");
		*New = &File->FileSystem->RootFile->EfiFile;
		/* Must make sure that DirIndex is reset too (NB: no concurrent access!) */
		File->FileSystem->RootFile->DirIndex = 0;
		PrintInfo(L"  RET: %llx\n", (UINT64) *New);
		return EFI_SUCCESS;
	}

	// TODO: eventually we should seek for already opened files and increase RefCount */
	/* Allocate and initialise an instance of a file */
	Status = GrubCreateFile(&NewFile, File->FileSystem);
	if (EFI_ERROR(Status)) {
		PrintStatusError(Status, L"Could not instantiate file");
		return Status;
	}

	NewFile->path = AllocatePool(strlena(clean_path)+1);
	if (NewFile->path == NULL) {
		GrubDestroyFile(NewFile);
		PrintError(L"Could not instantiate path\n");
		return EFI_OUT_OF_RESOURCES;
	}
	strcpya(NewFile->path, clean_path);

	/* Isolate the basename and dirname */
	// TODO: would be nicer to have those if path.c
	for (i = strlena(clean_path) - 1; i >= 0; i--) {
		if (clean_path[i] == '/') {
			clean_path[i] = 0;
			break;
		}
	}
	dirname = (i <= 0) ? "/" : clean_path;
	NewFile->basename = &NewFile->path[i+1];

	/* Find if we're working with a directory and fill the grub timestamp */
	Status = GrubDir(NewFile, dirname, InfoHook, (VOID *) NewFile);
	if (EFI_ERROR(Status)) {
		if (Status != EFI_NOT_FOUND)
			PrintStatusError(Status, L"Could not get file attributes for '%s'", Name);
		FreePool(NewFile->path);
		GrubDestroyFile(NewFile);
		return Status;
	}

	/* Finally we can call on GRUB open() if it's a regular file */
	if (!NewFile->IsDir) {
		Status = GrubOpen(NewFile);
		if (EFI_ERROR(Status)) {
			if (Status != EFI_NOT_FOUND)
				PrintStatusError(Status, L"Could not open file '%s'", Name);
			FreePool(NewFile->path);
			GrubDestroyFile(NewFile);
			return Status;
		}
	}

	NewFile->RefCount++;
	*New = &NewFile->EfiFile;

	PrintInfo(L"  RET: %llx\n", (UINT64) *New);
	return EFI_SUCCESS;
}
コード例 #3
0
ファイル: file.c プロジェクト: tribals/efifs
/**
 * Read directory entry
 *
 * @v file			EFI file
 * @v Len			Length to read
 * @v Data			Data buffer
 * @ret Status		EFI status code
 */
static EFI_STATUS
FileReadDir(EFI_GRUB_FILE *File, UINTN *Len, VOID *Data)
{
	EFI_FILE_INFO *Info = (EFI_FILE_INFO *) Data;
	EFI_STATUS Status;
	/* We temporarily repurpose the FileSize as a *signed* entry index */
	INT64 *Index = (INT64 *) &Info->FileSize;
	/* And PhysicalSize as a pointer to our filename */
	CHAR8 **basename = (CHAR8 **) &Info->PhysicalSize;
	CHAR8 path[MAX_PATH];
	EFI_GRUB_FILE *TmpFile = NULL;
	INTN len;

	/* Unless we can fit our maximum size, forget it */
	if (*Len < MINIMUM_INFO_LENGTH) {
		*Len = MINIMUM_INFO_LENGTH;
		return EFI_BUFFER_TOO_SMALL;
	}

	/* Populate our Info template */
	ZeroMem(Data, *Len);
	Info->Size = *Len;
	*Index = File->DirIndex;
	strcpya(path, File->path);
	len = strlena(path);
	if (path[len-1] != '/')
		path[len++] = '/';
	*basename = &path[len];

	/* Invoke GRUB's directory listing */
	Status = GrubDir(File, File->path, DirHook, Data);
	if (*Index >= 0) {
		/* No more entries */
		*Len = 0;
		return EFI_SUCCESS;
	}

	if (EFI_ERROR(Status)) {
		PrintStatusError(Status, L"Directory listing failed");
		return Status;
	}

	/* Our Index/FileSize must be reset */
	Info->FileSize = 0;
	Info->PhysicalSize = 0;

	/* For regular files, we still need to fill the size */
	if (!(Info->Attribute & EFI_FILE_DIRECTORY)) {
		/* Open the file and read its size */
		Status = GrubCreateFile(&TmpFile, File->FileSystem);
		if (EFI_ERROR(Status)) {
			PrintStatusError(Status, L"Unable to create temporary file");
			return Status;
		}
		TmpFile->path = path;

		Status = GrubOpen(TmpFile);
		if (EFI_ERROR(Status)) {
			// TODO: EFI_NO_MAPPING is returned for links...
			PrintStatusError(Status, L"Unable to obtain the size of '%s'", Info->FileName);
			/* Non fatal error */
		} else {
			Info->FileSize = GrubGetFileSize(TmpFile);
			Info->PhysicalSize = GrubGetFileSize(TmpFile);
			GrubClose(TmpFile);
		}
		GrubDestroyFile(TmpFile);
	}

	*Len = (UINTN) Info->Size;
	/* Advance to the next entry */
	File->DirIndex++;

//	PrintInfo(L"  Entry[%d]: '%s' %s\n", File->DirIndex-1, Info->FileName,
//			(Info->Attribute&EFI_FILE_DIRECTORY)?L"<DIR>":L"");

	return EFI_SUCCESS;
}
コード例 #4
0
ファイル: strops.c プロジェクト: jeppeter/elilo
CHAR8 *
strcata(IN CHAR8 *dst,IN CHAR8 *src)
{   
    return strcpya(dst+strlena(dst), src);
}