Ejemplo n.º 1
0
/**
  Reads the contents of the NvVars file on the file system

  @param[in]  FsHandle - Handle for a gEfiSimpleFileSystemProtocolGuid instance

  @return     EFI_STATUS based on the success or failure of the file read

**/
EFI_STATUS
ReadNvVarsFile (
  IN  EFI_HANDLE            FsHandle
  )
{
  EFI_STATUS                  Status;
  EFI_FILE_HANDLE             File;
  UINTN                       FileSize;
  BOOLEAN                     FileExists;
  VOID                        *FileContents;
  EFI_HANDLE                  SerializedVariables;

  Status = GetNvVarsFile (FsHandle, TRUE, &File);
  if (EFI_ERROR (Status)) {
    DEBUG ((EFI_D_INFO, "FsAccess.c: Could not open NV Variables file on this file system\n"));
    return Status;
  }

  NvVarsFileReadCheckup (File, &FileExists, &FileSize);
  if (FileSize == 0) {
    FileHandleClose (File);
    return EFI_UNSUPPORTED;
  }

  FileContents = FileHandleReadToNewBuffer (File, FileSize);
  if (FileContents == NULL) {
    FileHandleClose (File);
    return EFI_UNSUPPORTED;
  }

  DEBUG ((
    EFI_D_INFO,
    "FsAccess.c: Read %d bytes from NV Variables file\n",
    FileSize
    ));

  Status = SerializeVariablesNewInstanceFromBuffer (
             &SerializedVariables,
             FileContents,
             FileSize
             );
  if (!RETURN_ERROR (Status)) {
    Status = SerializeVariablesSetSerializedVariables (SerializedVariables);
  }

  FreePool (FileContents);
  FileHandleClose (File);

  return Status;
}
Ejemplo n.º 2
0
INTN EFIAPI ShellAppMain (IN UINTN Argc, IN CHAR16 **Argv) {
  CHAR8 c;
  int i;
  CHAR8 s[2];
  CHAR8 *source2 = source;
  EFI_FILE_HANDLE handle;
  UINTN size;
  for (i = 0; i < 4; i++) write_file(filenames[i], files[i]);
  ShellOpenFileByName(L"Quine.c", (void**)&handle,
    EFI_FILE_MODE_CREATE | EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE, 0);
  while (c = *source2++, c) {
    if (36 == c) {
      print_escape(handle, files[i++-4]);
    } else if (126 == c) {
      print_escape(handle, source);
    } else {
      s[0] = c; s[1] = 0;
      size = AsciiStrSize(s) - 1;
      FileHandleWrite(handle, &size, s);
    }
  }
  FileHandleClose(handle);
  Print(
   L" _____ _____ ___    ___        _            \n"
   L"| ____|  ___|_ _|  / _ \\ _   _(_)_ __   ___ \n"
   L"|  _| | |_   | |  | | | | | | | | '_ \\ / _ \\\n"
   L"| |___|  _|  | |  | |_| | |_| | | | | |  __/\n"
   L"|_____|_|   |___|  \\__\\_\\\\__,_|_|_| |_|\\___|\n"
  );

  return 0;
}
Ejemplo n.º 3
0
void write_file(CHAR16 *filename, CHAR8 *source) {
  EFI_FILE_HANDLE handle;
  UINTN size = AsciiStrSize(source) - 1;
  ShellOpenFileByName(filename, (void**)&handle,
    EFI_FILE_MODE_CREATE | EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE, 0);
  FileHandleWrite(handle, &size, source);
  FileHandleClose(handle);
}
Ejemplo n.º 4
0
/**
  Saves the non-volatile variables into the NvVars file on the
  given file system.

  @param[in]  FsHandle - Handle for a gEfiSimpleFileSystemProtocolGuid instance

  @return     EFI_STATUS based on the success or failure of load operation

**/
EFI_STATUS
SaveNvVarsToFs (
  EFI_HANDLE                            FsHandle
  )
{
  EFI_STATUS                  Status;
  EFI_FILE_HANDLE             File;
  UINTN                       WriteSize;
  UINTN                       VariableDataSize;
  VOID                        *VariableData;
  EFI_HANDLE                  SerializedVariables;

  SerializedVariables = NULL;

  Status = SerializeVariablesNewInstance (&SerializedVariables);
  if (EFI_ERROR (Status)) {
    return Status;
  }

  Status = SerializeVariablesIterateSystemVariables (
             IterateVariablesCallbackAddAllNvVariables,
             (VOID*) SerializedVariables
             );
  if (EFI_ERROR (Status)) {
    return Status;
  }

  VariableData = NULL;
  VariableDataSize = 0;
  Status = SerializeVariablesToBuffer (
             SerializedVariables,
             NULL,
             &VariableDataSize
             );
  if (Status == RETURN_BUFFER_TOO_SMALL) {
    VariableData = AllocatePool (VariableDataSize);
    if (VariableData == NULL) {
      Status = EFI_OUT_OF_RESOURCES;
    } else {
      Status = SerializeVariablesToBuffer (
                 SerializedVariables,
                 VariableData,
                 &VariableDataSize
                 );
    }
  }

  SerializeVariablesFreeInstance (SerializedVariables);

  if (EFI_ERROR (Status)) {
    return Status;
  }

  //
  // Open the NvVars file for writing.
  //
  Status = GetNvVarsFile (FsHandle, FALSE, &File);
  if (EFI_ERROR (Status)) {
    DEBUG ((EFI_D_INFO, "FsAccess.c: Unable to open file to saved NV Variables\n"));
    return Status;
  }

  //
  // Empty the starting file contents.
  //
  Status = FileHandleEmpty (File);
  if (EFI_ERROR (Status)) {
    FileHandleClose (File);
    return Status;
  }

  WriteSize = VariableDataSize;
  Status = FileHandleWrite (File, &WriteSize, VariableData);
  if (EFI_ERROR (Status)) {
    return Status;
  }

  FileHandleClose (File);

  if (!EFI_ERROR (Status)) {
    //
    // Write a variable to indicate we've already loaded the
    // variable data.  If it is found, we skip the loading on
    // subsequent attempts.
    //
    SetNvVarsVariable();

    DEBUG ((EFI_D_INFO, "Saved NV Variables to NvVars file\n"));
  }

  return Status;

}
Ejemplo n.º 5
0
/**
  Saves the non-volatile variables into the NvVars file on the
  given file system.

  @param[in]  FsHandle - Handle for a gEfiSimpleFileSystemProtocolGuid instance

  @return     EFI_STATUS based on the success or failure of load operation

**/
EFI_STATUS
SaveNvVarsToFs (
  EFI_HANDLE                            FsHandle
  )
{
  EFI_STATUS                  Status;
  EFI_FILE_HANDLE             File;
  UINTN                       VariableNameBufferSize;
  UINTN                       VariableNameSize;
  CHAR16                      *VariableName;
  EFI_GUID                    VendorGuid;
  UINTN                       VariableDataBufferSize;
  UINTN                       VariableDataSize;
  VOID                        *VariableData;
  UINT32                      VariableAttributes;
  VOID                        *NewBuffer;

  //
  // Open the NvVars file for writing.
  //
  Status = GetNvVarsFile (FsHandle, FALSE, &File);
  if (EFI_ERROR (Status)) {
    DEBUG ((EFI_D_INFO, "FsAccess.c: Unable to open file to saved NV Variables\n"));
    return Status;
  }

  //
  // Empty the starting file contents.
  //
  Status = FileHandleEmpty (File);
  if (EFI_ERROR (Status)) {
    FileHandleClose (File);
    return Status;
  }

  //
  // Initialize the variable name and data buffer variables.
  //
  VariableNameBufferSize = sizeof (CHAR16);
  VariableName = AllocateZeroPool (VariableNameBufferSize);

  VariableDataBufferSize = 0;
  VariableData = NULL;

  for (;;) {
    //
    // Get the next variable name and guid
    //
    VariableNameSize = VariableNameBufferSize;
    Status = gRT->GetNextVariableName (
                    &VariableNameSize,
                    VariableName,
                    &VendorGuid
                    );
    if (Status == EFI_BUFFER_TOO_SMALL) {
      //
      // The currently allocated VariableName buffer is too small,
      // so we allocate a larger buffer, and copy the old buffer
      // to it.
      //
      NewBuffer = AllocatePool (VariableNameSize);
      if (NewBuffer == NULL) {
        Status = EFI_OUT_OF_RESOURCES;
        break;
      }
      CopyMem (NewBuffer, VariableName, VariableNameBufferSize);
      if (VariableName != NULL) {
        FreePool (VariableName);
      }
      VariableName = NewBuffer;
      VariableNameBufferSize = VariableNameSize;

      //
      // Try to get the next variable name again with the larger buffer.
      //
      Status = gRT->GetNextVariableName (
                      &VariableNameSize,
                      VariableName,
                      &VendorGuid
                      );
    }

    if (EFI_ERROR (Status)) {
      if (Status == EFI_NOT_FOUND) {
        Status = EFI_SUCCESS;
      }
      break;
    }

    //
    // Get the variable data and attributes
    //
    VariableDataSize = VariableDataBufferSize;
    Status = gRT->GetVariable (
                    VariableName,
                    &VendorGuid,
                    &VariableAttributes,
                    &VariableDataSize,
                    VariableData
                    );
    if (Status == EFI_BUFFER_TOO_SMALL) {
      //
      // The currently allocated VariableData buffer is too small,
      // so we allocate a larger buffer.
      //
      if (VariableDataBufferSize != 0) {
        FreePool (VariableData);
        VariableData = NULL;
        VariableDataBufferSize = 0;
      }
      VariableData = AllocatePool (VariableDataSize);
      if (VariableData == NULL) {
        Status = EFI_OUT_OF_RESOURCES;
        break;
      }
      VariableDataBufferSize = VariableDataSize;

      //
      // Try to read the variable again with the larger buffer.
      //
      Status = gRT->GetVariable (
                      VariableName,
                      &VendorGuid,
                      &VariableAttributes,
                      &VariableDataSize,
                      VariableData
                      );
    }
    if (EFI_ERROR (Status)) {
      break;
    }

    //
    // Skip volatile variables.  We only preserve non-volatile variables.
    //
    if ((VariableAttributes & EFI_VARIABLE_NON_VOLATILE) == 0) {
      continue;
    }

    DEBUG ((
      EFI_D_INFO,
      "Saving variable %g:%s to file\n",
      &VendorGuid,
      VariableName
      ));

    //
    // Write the variable information out to the file
    //
    Status = PackVariableIntoFile (
               File,
               VariableName,
               (UINT32) VariableNameSize,
               &VendorGuid,
               VariableAttributes,
               VariableData,
               (UINT32) VariableDataSize
               );
    if (EFI_ERROR (Status)) {
      break;
    }

  }

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

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

  FileHandleClose (File);

  if (!EFI_ERROR (Status)) {
    DEBUG ((EFI_D_INFO, "Saved NV Variables to NvVars file\n"));
  }

  return Status;

}
Ejemplo n.º 6
0
/**
  Function to get a full filename given a EFI_FILE_HANDLE somewhere lower on the
  directory 'stack'. If the file is a directory, then append the '\' char at the 
  end of name string. If it's not a directory, then the last '\' should not be 
  added.

  if Handle is NULL, return EFI_INVALID_PARAMETER

  @param[in] Handle             Handle to the Directory or File to create path to.
  @param[out] FullFileName      pointer to pointer to generated full file name.  It
                                is the responsibility of the caller to free this memory
                                with a call to FreePool().
  @retval EFI_SUCCESS           the operation was sucessful and the FullFileName is valid.
  @retval EFI_INVALID_PARAMETER Handle was NULL.
  @retval EFI_INVALID_PARAMETER FullFileName was NULL.
  @retval EFI_OUT_OF_RESOURCES  a memory allocation failed.
**/
EFI_STATUS
EFIAPI
FileHandleGetFileName (
  IN CONST EFI_FILE_HANDLE      Handle,
  OUT CHAR16                    **FullFileName
  )
{
  EFI_STATUS      Status;
  UINTN           Size;
  EFI_FILE_HANDLE CurrentHandle;
  EFI_FILE_HANDLE NextHigherHandle;
  EFI_FILE_INFO   *FileInfo;

  Size = 0;

  //
  // Check our parameters
  //
  if (FullFileName == NULL || Handle == NULL) {
    return (EFI_INVALID_PARAMETER);
  }

  *FullFileName = NULL;
  CurrentHandle = NULL;

  Status = Handle->Open(Handle, &CurrentHandle, L".", EFI_FILE_MODE_READ, 0);
  if (!EFI_ERROR(Status)) {
    //
    // Reverse out the current directory on the device
    //
    for (;;) {
      FileInfo = FileHandleGetInfo(CurrentHandle);
      if (FileInfo == NULL) {
        Status = EFI_OUT_OF_RESOURCES;
        break;
      } else {
        //
        // We got info... do we have a name? if yes precede the current path with it...
        //
        if (StrLen (FileInfo->FileName) == 0) {
          if (*FullFileName == NULL) {
            ASSERT((*FullFileName == NULL && Size == 0) || (*FullFileName != NULL));
            *FullFileName = StrnCatGrowLeft(FullFileName, &Size, L"\\", 0);
          }
          FreePool(FileInfo);
          break;
        } else {
          if (*FullFileName == NULL) {
            ASSERT((*FullFileName == NULL && Size == 0) || (*FullFileName != NULL));
            *FullFileName = StrnCatGrowLeft(FullFileName, &Size, L"\\", 0);
          }
          ASSERT((*FullFileName == NULL && Size == 0) || (*FullFileName != NULL));
          *FullFileName = StrnCatGrowLeft(FullFileName, &Size, FileInfo->FileName, 0);
          *FullFileName = StrnCatGrowLeft(FullFileName, &Size, L"\\", 0);
          FreePool(FileInfo);
        }
      }
      //
      // Move to the parent directory
      //
      Status = CurrentHandle->Open (CurrentHandle, &NextHigherHandle, L"..", EFI_FILE_MODE_READ, 0);
      if (EFI_ERROR (Status)) {
        break;
      }

      FileHandleClose(CurrentHandle);
      CurrentHandle = NextHigherHandle;
    }
  } else if (Status == EFI_NOT_FOUND) {
    Status = EFI_SUCCESS;
    ASSERT((*FullFileName == NULL && Size == 0) || (*FullFileName != NULL));
    *FullFileName = StrnCatGrowLeft(FullFileName, &Size, L"\\", 0);
  }

  if (*FullFileName != NULL && 
      (*FullFileName)[StrLen(*FullFileName) - 1] == L'\\' && 
      StrLen(*FullFileName) > 1 &&
      FileHandleIsDirectory(Handle) == EFI_NOT_FOUND
     ) {
    (*FullFileName)[StrLen(*FullFileName) - 1] = CHAR_NULL;
  }

  if (CurrentHandle != NULL) {
    CurrentHandle->Close (CurrentHandle);
  }

  if (EFI_ERROR(Status) && *FullFileName != NULL) {
    FreePool(*FullFileName);
  }

  return (Status);
}
Ejemplo n.º 7
0
/**
  Dump capsule information from disk.

  @param[in] Fs                  The device path of disk.
  @param[in] DumpCapsuleInfo     The flag to indicate whether to dump the capsule inforomation.

  @retval EFI_SUCCESS            The capsule information is dumped.

**/
EFI_STATUS
DumpCapsuleFromDisk (
  IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL            *Fs,
  IN BOOLEAN                                    DumpCapsuleInfo
  )
{
  EFI_STATUS                                    Status;
  EFI_FILE                                      *Root;
  EFI_FILE                                      *DirHandle;
  EFI_FILE                                      *FileHandle;
  UINTN                                         Index;
  UINTN                                         FileSize;
  VOID                                          *FileBuffer;
  EFI_FILE_INFO                                 **FileInfoBuffer;
  EFI_FILE_INFO                                 *FileInfo;
  UINTN                                         FileCount;
  BOOLEAN                                       NoFile;

  DirHandle       = NULL;
  FileHandle      = NULL;
  Index           = 0;
  FileInfoBuffer  = NULL;
  FileInfo        = NULL;
  FileCount       = 0;
  NoFile          = FALSE;

  Status = Fs->OpenVolume (Fs, &Root);
  if (EFI_ERROR (Status)) {
    Print (L"Cannot open volume. Status = %r\n", Status);
    goto Done;
  }

  Status = Root->Open (Root, &DirHandle, EFI_CAPSULE_FILE_DIRECTORY, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE , 0);
  if (EFI_ERROR (Status)) {
    Print (L"Cannot open %s. Status = %r\n", EFI_CAPSULE_FILE_DIRECTORY, Status);
    goto Done;
  }

  //
  // Get file count first
  //
  do {
    Status = FileHandleFindFirstFile (DirHandle, &FileInfo);
    if (EFI_ERROR (Status) || FileInfo == NULL) {
      Print (L"Get File Info Fail. Status = %r\n", Status);
      goto Done;
    }

    if ((FileInfo->Attribute & (EFI_FILE_SYSTEM | EFI_FILE_ARCHIVE)) != 0) {
      FileCount++;
    }

    Status = FileHandleFindNextFile (DirHandle, FileInfo, &NoFile);
    if (EFI_ERROR (Status)) {
      Print (L"Get Next File Fail. Status = %r\n", Status);
      goto Done;
    }
  } while (!NoFile);

  if (FileCount == 0) {
    Print (L"Error: No capsule file found!\n");
    Status = EFI_NOT_FOUND;
    goto Done;
  }

  FileInfoBuffer = AllocateZeroPool (sizeof (FileInfo) * FileCount);
  if (FileInfoBuffer == NULL) {
    Status = EFI_OUT_OF_RESOURCES;
    goto Done;
  }
  NoFile = FALSE;

  //
  // Get all file info
  //
  do {
    Status = FileHandleFindFirstFile (DirHandle, &FileInfo);
    if (EFI_ERROR (Status) || FileInfo == NULL) {
      Print (L"Get File Info Fail. Status = %r\n", Status);
      goto Done;
    }

    if ((FileInfo->Attribute & (EFI_FILE_SYSTEM | EFI_FILE_ARCHIVE)) != 0) {
      FileInfoBuffer[Index++] = AllocateCopyPool ((UINTN)FileInfo->Size, FileInfo);
    }

    Status = FileHandleFindNextFile (DirHandle, FileInfo, &NoFile);
    if (EFI_ERROR (Status)) {
      Print (L"Get Next File Fail. Status = %r\n", Status);
      goto Done;
    }
  } while (!NoFile);

  //
  // Sort FileInfoBuffer by alphabet order
  //
  PerformQuickSort (
    FileInfoBuffer,
    FileCount,
    sizeof (FileInfo),
    (SORT_COMPARE) CompareFileNameInAlphabet
    );

  Print (L"The capsules will be performed by following order:\n");

  for (Index = 0; Index < FileCount; Index++) {
    Print (L"  %d.%s\n", Index + 1, FileInfoBuffer[Index]->FileName);
  }

  if (!DumpCapsuleInfo) {
    Status = EFI_SUCCESS;
    goto Done;
  }

  Print(L"The infomation of the capsules:\n");

  for (Index = 0; Index < FileCount; Index++) {
    FileHandle = NULL;
    Status = DirHandle->Open (DirHandle, &FileHandle, FileInfoBuffer[Index]->FileName, EFI_FILE_MODE_READ, 0);
    if (EFI_ERROR (Status)) {
      goto Done;
    }

    Status = FileHandleGetSize (FileHandle, (UINT64 *) &FileSize);
    if (EFI_ERROR (Status)) {
      Print (L"Cannot read file %s. Status = %r\n", FileInfoBuffer[Index]->FileName, Status);
      FileHandleClose (FileHandle);
      goto Done;
    }

    FileBuffer = AllocatePool (FileSize);
    if (FileBuffer == NULL) {
      Status = EFI_OUT_OF_RESOURCES;
      goto Done;
    }

    Status = FileHandleRead (FileHandle, &FileSize, FileBuffer);
    if (EFI_ERROR (Status)) {
      Print (L"Cannot read file %s. Status = %r\n", FileInfoBuffer[Index]->FileName, Status);
      FileHandleClose (FileHandle);
      FreePool (FileBuffer);
      goto Done;
    }

    Print (L"**************************\n");
    Print (L"  %d.%s:\n", Index + 1, FileInfoBuffer[Index]->FileName);
    Print (L"**************************\n");
    DumpCapsuleFromBuffer ((EFI_CAPSULE_HEADER *) FileBuffer);
    FileHandleClose (FileHandle);
    FreePool (FileBuffer);
  }

Done:
  if (FileInfoBuffer != NULL) {
    for (Index = 0; Index < FileCount; Index++) {
      if (FileInfoBuffer[Index] != NULL) {
        FreePool (FileInfoBuffer[Index]);
      }
    }
    FreePool (FileInfoBuffer);
  }

  return Status;
}
Ejemplo n.º 8
0
static void
ProcessRPM(const char *filename, PListEntry **files, PListEntry **dirs,
    char **ignore, const char *prefix, int stripcount)
{
	int		fd;
	FileHandle	*in;
	PListEntry	*last;

	if ((fd = open(filename, O_RDONLY, 0)) < 0) {
		perror(filename);
		exit(EXIT_FAILURE);
	}

	if (!IsRPMFile(fd)) {
		(void)fprintf(stderr, "%s: file is not an RPM package.\n",
		    filename);
		exit(EXIT_FAILURE);
	}

	if ((in = OpenRPM(&fd)) == NULL) {
		(void)fprintf(stderr, "%s: cannot get RPM data.\n", filename);
		exit(EXIT_FAILURE);
	}
	if (fd >= 0) {
		(void)close(fd);
		fd = -1;
	}

	last = NULL;
	for (;;) {
		unsigned long	fields[CPIO_NUM_HEADERS];
		char		*name;
		mode_t		mode;
		unsigned long	length;

		if (!GetCPIOHeader(in, fields, &name)) {
			(void)fprintf(stderr,
			    "%s: error in cpio header.\n",
			    filename);
			exit(EXIT_FAILURE);
		}
		if (strcmp(name, CPIO_END_MARKER) == 0) {
			free(name);
			break;
		}
		if (*name == '\0')
			fields[CPIO_HDR_MODE] = 0;

		if (ignore != NULL) {
			char **ptr;

			for (ptr = ignore; *ptr != NULL; ptr++) {
				if (CheckPrefix(*ptr, name)) {
					fields[CPIO_HDR_MODE] = 0;
					break;
				}
			}
		}

		if (fields[CPIO_HDR_MODE] != 0 &&
		    !StripPrefix(name, stripcount)) {
			(void)fprintf(stderr,
				    "%s: Leading path to strip too "
				    "big (-s %d)\n",
				    filename, stripcount);
			exit(EXIT_FAILURE);
		}

		if (prefix != NULL) {
			char *fullname;

		  	fullname = StrCat(prefix, name);
			free(name);
			name = fullname;
		}

		mode = ConvertMode(fields[CPIO_HDR_MODE]);
		length = fields[CPIO_HDR_FILESIZE];
		switch (fields[CPIO_HDR_MODE] & CP_IFMT) {
		case C_ISDIR: {
			PListEntry	*dir;
			bool		old_dir;

			if (length != 0) {
				(void)fprintf(stderr,
				    "%s: error in cpio file.\n",
				filename);
				exit(EXIT_FAILURE);
			}

			if (!MakeTargetDir(name, dirs)) {
				(void)fprintf(stderr,
				    "%s: can't create parent "
				    "directories for \"%s\".\n",
		                    filename, name);
				exit(EXIT_FAILURE);
			}

			if (!MakeDir(name, mode, &old_dir)) {
				(void)fprintf(stderr,
				    "%s: can't create directory "
				    "\"%s\".\n", filename, name);
				exit(EXIT_FAILURE);
			}

			if (!old_dir) {
				dir = PListInsert(dirs, name);
				dir->pe_DirEmpty = true;
			}
			break;
		}
		case C_ISLNK: {
			char *link_target;

			if ((link_target = GetData(in, length)) == NULL) {
				(void)fprintf(stderr,
				    "%s: error in cpio file.\n",
				filename);
				exit(EXIT_FAILURE);
			}

			if (!MakeTargetDir(name, dirs)) {
				(void)fprintf(stderr,
				    "%s: can't create parent "
				    "directories for \"%s\".\n",
		                    filename, name);
				exit(EXIT_FAILURE);
			}

			if (*link_target == '/') {
				char *ptr;

				(void)memmove(link_target, link_target + 1,
				    strlen(link_target));
				ptr = name;
				if (prefix != NULL)
					ptr += strlen(prefix);

				while ((ptr = strchr(ptr, '/')) != NULL) {
					char *new_link_target;

				    	new_link_target = StrCat("../",
					    link_target);
					free(link_target);
					link_target = new_link_target;
					ptr++;
				}
			}

			if (!MakeSymLink(link_target, name)) {
				(void)fprintf(stderr,
				    "%s: can't create symbolic link "
				    "\"%s\".\n", filename, name);
				exit(EXIT_FAILURE);
			}

	    		PListInsert(files, name)->pe_Link = link_target;
			break;
		}
		case C_ISREG:
			if (!MakeTargetDir(name, dirs)) {
				(void)fprintf(stderr,
				    "%s: can't create parent "
				    "directories for \"%s\".\n",
		                    filename, name);
				exit(EXIT_FAILURE);
			}


			if ((last != NULL) && (last->pe_INode !=
			    fields[CPIO_HDR_INODE])) {
				last = NULL;
			}

			if (!WriteFile(in, name, mode, length,
			    (last != NULL)? last->pe_Name : NULL)) {
				(void)fprintf(stderr,
		                    "%s: can't write file \"%s\".\n",
		                    filename, name);
				exit(EXIT_FAILURE);
			}

			last = PListInsert(files, name);
			last->pe_INode = fields[CPIO_HDR_INODE];
			break;
		default:
			if (length > 0 && !SkipAndAlign(in, length)) {
				(void)fprintf(stderr,
				    "%s: error in cpio file.\n",
				    filename);
				exit(EXIT_FAILURE);
			}
					
		}

		free(name);
	}

	FileHandleClose(in);
}