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; }
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; }
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; }
// // 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; }