Beispiel #1
0
fsw_status_t fsw_posix_open_dno(struct fsw_posix_volume *pvol, const char *path, int required_type, struct fsw_shandle *shand)
{
    fsw_status_t        status;
    struct fsw_dnode    *dno;
    struct fsw_dnode    *target_dno;
    struct fsw_string   lookup_path;
    
    lookup_path.type = FSW_STRING_TYPE_ISO88591;
    lookup_path.len  = strlen(path);
    lookup_path.size = lookup_path.len;
    lookup_path.data = (void *)path;
    
    // resolve the path (symlinks along the way are automatically resolved)
    status = fsw_dnode_lookup_path(pvol->vol->root, &lookup_path, '/', &dno);
    if (status) {
        fprintf(stderr, "fsw_posix_open_dno: fsw_dnode_lookup_path returned %d\n", status);
        return status;
    }
    
    // if the final node is a symlink, also resolve it
    status = fsw_dnode_resolve(dno, &target_dno);
    fsw_dnode_release(dno);
    if (status) {
        fprintf(stderr, "fsw_posix_open_dno: fsw_dnode_resolve returned %d\n", status);
        return status;
    }
    dno = target_dno;
    
    // check that it is a regular file
    status = fsw_dnode_fill(dno);
    if (status) {
        fprintf(stderr, "fsw_posix_open_dno: fsw_dnode_fill returned %d\n", status);
        fsw_dnode_release(dno);
        return status;
    }
    if (dno->type != required_type) {
        fprintf(stderr, "fsw_posix_open_dno: dnode is not of the requested type\n");
        fsw_dnode_release(dno);
        return FSW_UNSUPPORTED;
    }
    
    // open shandle
    status = fsw_shandle_open(dno, shand);
    if (status) {
        fprintf(stderr, "fsw_posix_open_dno: fsw_shandle_open returned %d\n", status);
    }
    fsw_dnode_release(dno);
    return status;
}
void fsw_dnode_release(struct fsw_dnode *dno)
{
    struct fsw_volume *vol = dno->vol;
    struct fsw_dnode *parent_dno;

    dno->refcount--;

    if (dno->refcount == 0) {
        parent_dno = dno->parent;

        // de-register from volume's list
        if (dno->next)
            dno->next->prev = dno->prev;
        if (dno->prev)
            dno->prev->next = dno->next;
        if (vol->dnode_head == dno)
            vol->dnode_head = dno->next;

        // run fstype-specific cleanup
        vol->fstype_table->dnode_free(vol, dno);

        fsw_strfree(&dno->name);
        fsw_free(dno);

        // release our pointer to the parent, possibly deallocating it, too
        if (parent_dno)
            fsw_dnode_release(parent_dno);
    }
}
Beispiel #3
0
EFI_STATUS fsw_efi_dir_read(IN FSW_FILE_DATA *File,
                            IN OUT UINTN *BufferSize,
                            OUT VOID *Buffer)
{
    EFI_STATUS          Status;
    FSW_VOLUME_DATA     *Volume = (FSW_VOLUME_DATA *)File->shand.dnode->vol->host_data;
    struct fsw_dnode    *dno;

#if DEBUG_LEVEL
    Print(L"fsw_efi_dir_read...\n");
#endif

    // read the next entry
    Status = fsw_efi_map_status(fsw_dnode_dir_read(&File->shand, &dno),
                                Volume);
    if (Status == EFI_NOT_FOUND) {
        // end of directory
        *BufferSize = 0;
#if DEBUG_LEVEL
        Print(L"...no more entries\n");
#endif
        return EFI_SUCCESS;
    }
    if (EFI_ERROR(Status))
        return Status;

    // get info into buffer
    Status = fsw_efi_dnode_fill_FileInfo(Volume, dno, BufferSize, Buffer);
    fsw_dnode_release(dno);
    return Status;
}
Beispiel #4
0
fsw_status_t fsw_dnode_resolve(struct fsw_dnode *dno, struct fsw_dnode **target_dno_out)
{
    fsw_status_t    status;
    struct fsw_string target_name;
    struct fsw_dnode *target_dno;
    /* Linux kernel max link count is 40 */
    int link_count = 40;

    fsw_dnode_retain(dno);

    while (--link_count > 0) {
        // get full information
        status = fsw_dnode_fill(dno);
        if (status)
            goto errorexit;
        if (dno->type != FSW_DNODE_TYPE_SYMLINK) {
            // found a non-symlink target, return it
            *target_dno_out = dno;
            return FSW_SUCCESS;
        }
        if (dno->parent == NULL) {    // safety measure, cannot happen in theory
            status = FSW_NOT_FOUND;
            goto errorexit;
        }

        // read the link's target
        status = fsw_dnode_readlink(dno, &target_name);
        if (status)
            goto errorexit;

        // resolve it
        status = fsw_dnode_lookup_path(dno->parent, &target_name, '/', &target_dno);
        fsw_strfree(&target_name);
        if (status)
            goto errorexit;

        // target_dno becomes the new dno
        fsw_dnode_release(dno);
        dno = target_dno;   // is already retained
    }
    if(link_count == 0)
      status = FSW_NOT_FOUND;

errorexit:
    fsw_dnode_release(dno);
    return status;
}
Beispiel #5
0
EFI_STATUS fsw_efi_dir_open(IN FSW_FILE_DATA *File,
                            OUT EFI_FILE_PROTOCOL **NewHandle,
                            IN CHAR16 *FileName,
                            IN UINT64 OpenMode,
                            IN UINT64 Attributes)
{
    EFI_STATUS          Status;
    FSW_VOLUME_DATA     *Volume = (FSW_VOLUME_DATA *)File->shand.dnode->vol->host_data;
    struct fsw_dnode    *dno;
    struct fsw_dnode    *target_dno;
    struct fsw_string   lookup_path;

#if DEBUG_LEVEL
    Print(L"fsw_efi_dir_open: '%s'\n", FileName);
#endif

    if (OpenMode != EFI_FILE_MODE_READ)
        return EFI_WRITE_PROTECTED;

    lookup_path.type = FSW_STRING_TYPE_UTF16;
    lookup_path.len  = (int)StrLen(FileName);
    lookup_path.size = lookup_path.len * sizeof(fsw_u16);
    lookup_path.data = FileName;

    // resolve the path (symlinks along the way are automatically resolved)
    Status = fsw_efi_map_status(fsw_dnode_lookup_path(File->shand.dnode,
                                                      &lookup_path, '\\',
                                                      &dno),
                                Volume);
    if (EFI_ERROR(Status))
        return Status;

    // if the final node is a symlink, also resolve it
    Status = fsw_efi_map_status(fsw_dnode_resolve(dno, &target_dno),
                                Volume);
    fsw_dnode_release(dno);
    if (EFI_ERROR(Status))
        return Status;
    dno = target_dno;

    // make a new EFI handle for the target dnode
    Status = fsw_efi_dnode_to_FileHandle(dno, NewHandle);
    fsw_dnode_release(dno);
    return Status;
}
void fsw_unmount(struct fsw_volume *vol)
{
    if (vol->root)
        fsw_dnode_release(vol->root);
    /// @todo check that no other dnodes are still around

    vol->fstype_table->volume_free(vol);

    fsw_blockcache_free(vol);
    fsw_strfree(&vol->label);
    fsw_free(vol);
}
Beispiel #7
0
struct dirent * fsw_posix_readdir(struct fsw_posix_dir *dir)
{
    fsw_status_t        status;
    struct fsw_dnode    *dno;
    static struct dirent dent;
    
    // get next entry from file system
    status = fsw_dnode_dir_read(&dir->shand, &dno);
    if (status) {
        fprintf(stderr, "fsw_posix_readdir: fsw_dnode_dir_read returned %d\n", status);
        return NULL;
    }
    status = fsw_dnode_fill(dno);
    if (status) {
        fprintf(stderr, "fsw_posix_readdir: fsw_dnode_fill returned %d\n", status);
        fsw_dnode_release(dno);
        return NULL;
    }
    
    // fill dirent structure
    dent.d_fileno = dno->dnode_id;
    dent.d_reclen = 8 + dno->name.size + 1;
    switch (dno->type) {
        case FSW_DNODE_TYPE_FILE:
            dent.d_type = DT_REG;
            break;
        case FSW_DNODE_TYPE_DIR:
            dent.d_type = DT_DIR;
            break;
        case FSW_DNODE_TYPE_SYMLINK:
            dent.d_type = DT_LNK;
            break;
        default:
            dent.d_type = DT_UNKNOWN;
            break;
    }
    dent.d_namlen = dno->name.size;
    memcpy(dent.d_name, dno->name.data, dno->name.size);
    dent.d_name[dent.d_namlen] = 0;
    
    return &dent;
}
void fsw_shandle_close(struct fsw_shandle *shand)
{
    if (shand->extent.type == FSW_EXTENT_TYPE_BUFFER)
        fsw_free(shand->extent.buffer);
    fsw_dnode_release(shand->dnode);
}
fsw_status_t fsw_dnode_lookup_path(struct fsw_dnode *dno,
                                   struct fsw_string *lookup_path, char separator,
                                   struct fsw_dnode **child_dno_out)
{
    fsw_status_t    status;
    struct fsw_volume *vol = dno->vol;
    struct fsw_dnode *child_dno = NULL;
    struct fsw_string lookup_name;
    struct fsw_string remaining_path;
    int             root_if_empty;

    remaining_path = *lookup_path;
    fsw_dnode_retain(dno);

    // loop over the path
    for (root_if_empty = 1; fsw_strlen(&remaining_path) > 0; root_if_empty = 0) {
        // parse next path component
        fsw_strsplit(&lookup_name, &remaining_path, separator);

        FSW_MSG_DEBUG((FSW_MSGSTR("fsw_dnode_lookup_path: split into %d '%s' and %d '%s'\n"),
                       lookup_name.len, lookup_name.data,
                       remaining_path.len, remaining_path.data));

        if (fsw_strlen(&lookup_name) == 0) {        // empty path component
            if (root_if_empty)
                child_dno = vol->root;
            else
                child_dno = dno;
            fsw_dnode_retain(child_dno);

        } else {
            // do an actual directory lookup

            // ensure we have full information
            status = fsw_dnode_fill(dno);
            if (status)
                goto errorexit;

            // resolve symlink if necessary
            if (dno->type == FSW_DNODE_TYPE_SYMLINK) {
                status = fsw_dnode_resolve(dno, &child_dno);
                if (status)
                    goto errorexit;

                // symlink target becomes the new dno
                fsw_dnode_release(dno);
                dno = child_dno;   // is already retained
                child_dno = NULL;

                // ensure we have full information
                status = fsw_dnode_fill(dno);
                if (status)
                    goto errorexit;
            }

            // make sure we operate on a directory
            if (dno->type != FSW_DNODE_TYPE_DIR) {
                return FSW_UNSUPPORTED;
                goto errorexit;
            }

            // check special paths
            if (fsw_streq_cstr(&lookup_name, ".")) {    // self directory
                child_dno = dno;
                fsw_dnode_retain(child_dno);

            } else if (fsw_streq_cstr(&lookup_name, "..")) {   // parent directory
                if (dno->parent == NULL) {
                    // We cannot go up from the root directory. Caution: Certain apps like the EFI shell
                    // rely on this behaviour!
                    status = FSW_NOT_FOUND;
                    goto errorexit;
                }
                child_dno = dno->parent;
                fsw_dnode_retain(child_dno);

            } else {
                // do an actual lookup
                status = vol->fstype_table->dir_lookup(vol, dno, &lookup_name, &child_dno);
                if (status)
                    goto errorexit;
            }
        }

        // child_dno becomes the new dno
        fsw_dnode_release(dno);
        dno = child_dno;   // is already retained
        child_dno = NULL;

        FSW_MSG_DEBUG((FSW_MSGSTR("fsw_dnode_lookup_path: now at inode %d\n"), dno->dnode_id));
    }

    *child_dno_out = dno;
    return FSW_SUCCESS;

errorexit:
    FSW_MSG_DEBUG((FSW_MSGSTR("fsw_dnode_lookup_path: leaving with error %d\n"), status));
    fsw_dnode_release(dno);
    if (child_dno != NULL)
        fsw_dnode_release(child_dno);
    return status;
}
Beispiel #10
0
//
// Common function to fill an EFI_FILE_INFO with information about a dnode.
// there is caller responsible to allocate buffer
//
EFI_STATUS fsw_efi_dnode_fill_FileInfo(IN FSW_VOLUME_DATA *Volume,
                                       IN struct fsw_dnode *dno,
                                       IN OUT UINTN *BufferSize,
                                       OUT VOID *Buffer)
{
  EFI_STATUS          Status;
  EFI_FILE_INFO       *FileInfo;
  UINTN               RequiredSize;
  struct fsw_dnode_stat_str sb;
  struct fsw_dnode *target_dno;
  
  // make sure the dnode has complete info
  Status = fsw_efi_map_status(fsw_dnode_fill(dno), Volume);
  if (EFI_ERROR(Status))
    return Status;
  
  // TODO: check/assert that the dno's name is in UTF16
  
  // check buffer size
  RequiredSize = SIZE_OF_EFI_FILE_INFO + fsw_efi_strsize(&dno->name);
  if (*BufferSize < RequiredSize) {
    // TODO: wind back the directory in this case
    
#if DEBUG_LEVEL
    Print(L"...BUFFER TOO SMALL\n");
#endif
    *BufferSize = RequiredSize;
    return EFI_BUFFER_TOO_SMALL;
  }
  
  // fill structure
  ZeroMem (Buffer, RequiredSize);
  FileInfo = (EFI_FILE_INFO *) Buffer;
  
  // Use original name (name of symlink if any)
  fsw_efi_strcpy (FileInfo->FileName, &dno->name);
  
  // if the node is a symlink, resolve it
  Status = fsw_efi_map_status (fsw_dnode_resolve (dno, &target_dno), Volume);
  fsw_dnode_release (dno);
  if (EFI_ERROR (Status))
    return Status;
  dno = target_dno;
  
  // make sure the dnode has complete info
  Status = fsw_efi_map_status (fsw_dnode_fill (dno), Volume);
  if (EFI_ERROR (Status))
    return Status;
  
  FileInfo->Size = RequiredSize;
  FileInfo->FileSize          = dno->size;
  FileInfo->Attribute         = EFI_FILE_READ_ONLY;
  if (dno->type == FSW_DNODE_TYPE_DIR)
    FileInfo->Attribute    |= EFI_FILE_DIRECTORY;
  
  // get the missing info from the fs driver
  ZeroMem(&sb, sizeof(struct fsw_dnode_stat_str));
  sb.store_time_posix = fsw_efi_store_time_posix;
  sb.store_attr_posix = fsw_efi_store_attr_posix;
  sb.host_data = FileInfo;
  Status = fsw_efi_map_status(fsw_dnode_stat(dno, &sb), Volume);
  if (EFI_ERROR(Status))
    return Status;
  FileInfo->PhysicalSize      = sb.used_bytes;
  
  // prepare for return
  *BufferSize = RequiredSize;
#if DEBUG_LEVEL
  Print(L"...returning '%s'\n", FileInfo->FileName);
#endif
  return EFI_SUCCESS;
}