Ejemplo n.º 1
0
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 sb;

    // 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;
    FileInfo->Size = RequiredSize;
    FileInfo->FileSize          = dno->size;
    FileInfo->Attribute         = 0;
    if (dno->type == FSW_DNODE_TYPE_DIR)
        FileInfo->Attribute    |= EFI_FILE_DIRECTORY;
    fsw_efi_strcpy(FileInfo->FileName, &dno->name);

    // get the missing info from the fs driver
    ZeroMem(&sb, sizeof(struct fsw_dnode_stat));
    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;
}
Ejemplo n.º 2
0
EFI_STATUS fsw_efi_dnode_to_FileHandle(IN struct fsw_dnode *dno,
                                       OUT EFI_FILE **NewFileHandle)
{
    EFI_STATUS          Status;
    FSW_FILE_DATA       *File;

    FSW_MSG_DEBUG((FSW_MSGSTR(__FUNCTION__ ": enter\n")));
    // make sure the dnode has complete info
    Status = fsw_efi_map_status(fsw_dnode_fill(dno), (FSW_VOLUME_DATA *)dno->vol->host_data);
    if (EFI_ERROR(Status)) {
        goto Done;
    }

    // check type
    if (dno->type != FSW_DNODE_TYPE_FILE && dno->type != FSW_DNODE_TYPE_DIR) {
        Status = EFI_UNSUPPORTED;
	goto Done;
    }

    // allocate file structure
    File = AllocateZeroPool(sizeof(FSW_FILE_DATA));
    File->Signature = FSW_FILE_DATA_SIGNATURE;
    if (dno->type == FSW_DNODE_TYPE_FILE)
        File->Type = FSW_EFI_FILE_TYPE_FILE;
    else if (dno->type == FSW_DNODE_TYPE_DIR)
        File->Type = FSW_EFI_FILE_TYPE_DIR;

    // open shandle
    Status = fsw_efi_map_status(fsw_shandle_open(dno, &File->shand),
                                (FSW_VOLUME_DATA *)dno->vol->host_data);
    if (EFI_ERROR(Status)) {
        FreePool(File);
        goto Done;
    }

    // populate the file handle
    File->FileHandle.Revision    = EFI_FILE_HANDLE_REVISION;
    File->FileHandle.Open        = fsw_efi_FileHandle_Open;
    File->FileHandle.Close       = fsw_efi_FileHandle_Close;
    File->FileHandle.Delete      = fsw_efi_FileHandle_Delete;
    File->FileHandle.Read        = fsw_efi_FileHandle_Read;
    File->FileHandle.Write       = fsw_efi_FileHandle_Write;
    File->FileHandle.GetPosition = fsw_efi_FileHandle_GetPosition;
    File->FileHandle.SetPosition = fsw_efi_FileHandle_SetPosition;
    File->FileHandle.GetInfo     = fsw_efi_FileHandle_GetInfo;
    File->FileHandle.SetInfo     = fsw_efi_FileHandle_SetInfo;
    File->FileHandle.Flush       = fsw_efi_FileHandle_Flush;

    *NewFileHandle = &File->FileHandle;
    Status = EFI_SUCCESS;

Done:
    FSW_MSG_DEBUG((FSW_MSGSTR(__FUNCTION__ ": leaving with %r\n"), Status));
    return Status;
}
fsw_status_t fsw_dnode_readlink(struct fsw_dnode *dno, struct fsw_string *target_name)
{
    fsw_status_t    status;

    status = fsw_dnode_fill(dno);
    if (status)
        return status;
    if (dno->type != FSW_DNODE_TYPE_SYMLINK)
        return FSW_UNSUPPORTED;

    return dno->vol->fstype_table->readlink(dno->vol, dno, target_name);
}
fsw_status_t fsw_dnode_lookup(struct fsw_dnode *dno,
                              struct fsw_string *lookup_name, struct fsw_dnode **child_dno_out)
{
    fsw_status_t    status;

    status = fsw_dnode_fill(dno);
    if (status)
        return status;
    if (dno->type != FSW_DNODE_TYPE_DIR)
        return FSW_UNSUPPORTED;

    return dno->vol->fstype_table->dir_lookup(dno->vol, dno, lookup_name, child_dno_out);
}
fsw_status_t fsw_dnode_stat(struct fsw_dnode *dno, struct fsw_dnode_stat *sb)
{
    fsw_status_t    status;

    status = fsw_dnode_fill(dno);
    if (status)
        return status;

    sb->used_bytes = 0;
    status = dno->vol->fstype_table->dnode_stat(dno->vol, dno, sb);
    if (!status && !sb->used_bytes)
        sb->used_bytes = FSW_U64_DIV(dno->size + dno->vol->log_blocksize - 1, dno->vol->log_blocksize);
    return status;
}
Ejemplo n.º 6
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;
}
Ejemplo n.º 7
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;
}
Ejemplo n.º 8
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;
}
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;
}