mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-11-22 20:06:40 +00:00
haze: implement GetObjectPropList
This commit is contained in:
parent
e8ac23e2ee
commit
c866c15856
6 changed files with 149 additions and 3 deletions
|
@ -111,6 +111,14 @@ namespace haze {
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr void Deallocate(void *p, size_t n) {
|
constexpr void Deallocate(void *p, size_t n) {
|
||||||
|
/* Check for overflow in alignment. */
|
||||||
|
if (!util::CanAddWithoutOverflow(n, alignof(u64) - 1)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Align the amount to satisfy allocation for u64. */
|
||||||
|
n = util::AlignUp(n, alignof(u64));
|
||||||
|
|
||||||
/* If the pointer was the last allocation, return the memory to the heap. */
|
/* If the pointer was the last allocation, return the memory to the heap. */
|
||||||
if (static_cast<u8 *>(p) + n == this->GetNextAddress()) {
|
if (static_cast<u8 *>(p) + n == this->GetNextAddress()) {
|
||||||
m_next_address = this->GetNextAddress() - n;
|
m_next_address = this->GetNextAddress() - n;
|
||||||
|
|
|
@ -83,6 +83,7 @@ namespace haze {
|
||||||
Result GetObjectPropDesc(PtpDataParser &dp);
|
Result GetObjectPropDesc(PtpDataParser &dp);
|
||||||
Result GetObjectPropValue(PtpDataParser &dp);
|
Result GetObjectPropValue(PtpDataParser &dp);
|
||||||
Result SetObjectPropValue(PtpDataParser &dp);
|
Result SetObjectPropValue(PtpDataParser &dp);
|
||||||
|
Result GetObjectPropList(PtpDataParser &dp);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,6 +57,7 @@ namespace haze {
|
||||||
PtpOperationCode_MtpGetObjectPropDesc,
|
PtpOperationCode_MtpGetObjectPropDesc,
|
||||||
PtpOperationCode_MtpGetObjectPropValue,
|
PtpOperationCode_MtpGetObjectPropValue,
|
||||||
PtpOperationCode_MtpSetObjectPropValue,
|
PtpOperationCode_MtpSetObjectPropValue,
|
||||||
|
PtpOperationCode_MtpGetObjPropList,
|
||||||
PtpOperationCode_AndroidGetPartialObject64,
|
PtpOperationCode_AndroidGetPartialObject64,
|
||||||
PtpOperationCode_AndroidSendPartialObject,
|
PtpOperationCode_AndroidSendPartialObject,
|
||||||
PtpOperationCode_AndroidTruncateObject,
|
PtpOperationCode_AndroidTruncateObject,
|
||||||
|
|
|
@ -38,5 +38,7 @@ namespace haze {
|
||||||
R_DEFINE_ERROR_RESULT(UnknownPropertyCode, 14);
|
R_DEFINE_ERROR_RESULT(UnknownPropertyCode, 14);
|
||||||
R_DEFINE_ERROR_RESULT(InvalidPropertyValue, 15);
|
R_DEFINE_ERROR_RESULT(InvalidPropertyValue, 15);
|
||||||
R_DEFINE_ERROR_RESULT(InvalidArgument, 16);
|
R_DEFINE_ERROR_RESULT(InvalidArgument, 16);
|
||||||
|
R_DEFINE_ERROR_RESULT(GroupSpecified, 17);
|
||||||
|
R_DEFINE_ERROR_RESULT(DepthSpecified, 18);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,6 +91,12 @@ namespace haze {
|
||||||
R_CATCH(haze::ResultInvalidPropertyValue) {
|
R_CATCH(haze::ResultInvalidPropertyValue) {
|
||||||
R_TRY(this->WriteResponse(PtpResponseCode_MtpInvalidObjectPropValue));
|
R_TRY(this->WriteResponse(PtpResponseCode_MtpInvalidObjectPropValue));
|
||||||
}
|
}
|
||||||
|
R_CATCH(haze::ResultGroupSpecified) {
|
||||||
|
R_TRY(this->WriteResponse(PtpResponseCode_MtpSpecificationByGroupUnsupported));
|
||||||
|
}
|
||||||
|
R_CATCH(haze::ResultDepthSpecified) {
|
||||||
|
R_TRY(this->WriteResponse(PtpResponseCode_MtpSpecificationByDepthUnsupported));
|
||||||
|
}
|
||||||
R_CATCH(haze::ResultInvalidArgument) {
|
R_CATCH(haze::ResultInvalidArgument) {
|
||||||
R_TRY(this->WriteResponse(PtpResponseCode_GeneralError));
|
R_TRY(this->WriteResponse(PtpResponseCode_GeneralError));
|
||||||
}
|
}
|
||||||
|
@ -134,6 +140,7 @@ namespace haze {
|
||||||
case PtpOperationCode_MtpGetObjectPropDesc: R_RETURN(this->GetObjectPropDesc(dp)); break;
|
case PtpOperationCode_MtpGetObjectPropDesc: R_RETURN(this->GetObjectPropDesc(dp)); break;
|
||||||
case PtpOperationCode_MtpGetObjectPropValue: R_RETURN(this->GetObjectPropValue(dp)); break;
|
case PtpOperationCode_MtpGetObjectPropValue: R_RETURN(this->GetObjectPropValue(dp)); break;
|
||||||
case PtpOperationCode_MtpSetObjectPropValue: R_RETURN(this->SetObjectPropValue(dp)); break;
|
case PtpOperationCode_MtpSetObjectPropValue: R_RETURN(this->SetObjectPropValue(dp)); break;
|
||||||
|
case PtpOperationCode_MtpGetObjPropList: R_RETURN(this->GetObjectPropList(dp)); break;
|
||||||
case PtpOperationCode_AndroidGetPartialObject64: R_RETURN(this->GetPartialObject64(dp)); break;
|
case PtpOperationCode_AndroidGetPartialObject64: R_RETURN(this->GetPartialObject64(dp)); break;
|
||||||
case PtpOperationCode_AndroidSendPartialObject: R_RETURN(this->SendPartialObject(dp)); break;
|
case PtpOperationCode_AndroidSendPartialObject: R_RETURN(this->SendPartialObject(dp)); break;
|
||||||
case PtpOperationCode_AndroidTruncateObject: R_RETURN(this->TruncateObject(dp)); break;
|
case PtpOperationCode_AndroidTruncateObject: R_RETURN(this->TruncateObject(dp)); break;
|
||||||
|
|
|
@ -113,9 +113,6 @@ namespace haze {
|
||||||
R_TRY(dp.Read(std::addressof(property_code)));
|
R_TRY(dp.Read(std::addressof(property_code)));
|
||||||
R_TRY(dp.Finalize());
|
R_TRY(dp.Finalize());
|
||||||
|
|
||||||
/* Disallow renaming the storage root. */
|
|
||||||
R_UNLESS(object_id != StorageId_SdmcFs, haze::ResultInvalidObjectId());
|
|
||||||
|
|
||||||
/* Ensure we have a valid property code before continuing. */
|
/* Ensure we have a valid property code before continuing. */
|
||||||
R_UNLESS(IsSupportedObjectPropertyCode(property_code), haze::ResultUnknownPropertyCode());
|
R_UNLESS(IsSupportedObjectPropertyCode(property_code), haze::ResultUnknownPropertyCode());
|
||||||
|
|
||||||
|
@ -198,6 +195,136 @@ namespace haze {
|
||||||
R_RETURN(this->WriteResponse(PtpResponseCode_Ok));
|
R_RETURN(this->WriteResponse(PtpResponseCode_Ok));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result PtpResponder::GetObjectPropList(PtpDataParser &dp) {
|
||||||
|
u32 object_id;
|
||||||
|
u32 object_format;
|
||||||
|
s32 property_code;
|
||||||
|
s32 group_code;
|
||||||
|
s32 depth;
|
||||||
|
|
||||||
|
R_TRY(dp.Read(std::addressof(object_id)));
|
||||||
|
R_TRY(dp.Read(std::addressof(object_format)));
|
||||||
|
R_TRY(dp.Read(std::addressof(property_code)));
|
||||||
|
R_TRY(dp.Read(std::addressof(group_code)));
|
||||||
|
R_TRY(dp.Read(std::addressof(depth)));
|
||||||
|
R_TRY(dp.Finalize());
|
||||||
|
|
||||||
|
/* Ensure format is unspecified. */
|
||||||
|
R_UNLESS(object_format == 0, haze::ResultInvalidArgument());
|
||||||
|
|
||||||
|
/* Ensure we have a valid property code. */
|
||||||
|
R_UNLESS(property_code == -1 || IsSupportedObjectPropertyCode(PtpObjectPropertyCode(property_code)), haze::ResultUnknownPropertyCode());
|
||||||
|
|
||||||
|
/* Ensure group code is the default. */
|
||||||
|
R_UNLESS(group_code == PtpPropertyGroupCode_Default, haze::ResultGroupSpecified());
|
||||||
|
|
||||||
|
/* Ensure depth is 0. */
|
||||||
|
R_UNLESS(depth == 0, haze::ResultDepthSpecified());
|
||||||
|
|
||||||
|
/* Check if we know about the object. If we don't, it's an error. */
|
||||||
|
auto * const obj = m_object_database.GetObjectById(object_id);
|
||||||
|
R_UNLESS(obj != nullptr, haze::ResultInvalidObjectId());
|
||||||
|
|
||||||
|
/* Define helper for getting the object type. */
|
||||||
|
const auto GetObjectType = [&] (FsDirEntryType *out_entry_type) {
|
||||||
|
R_RETURN(m_fs.GetEntryType(obj->GetName(), out_entry_type));
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Define helper for getting the object size. */
|
||||||
|
const auto GetObjectSize = [&] (s64 *out_size) {
|
||||||
|
*out_size = 0;
|
||||||
|
|
||||||
|
/* Check if this is a directory. */
|
||||||
|
FsDirEntryType entry_type;
|
||||||
|
R_TRY(GetObjectType(std::addressof(entry_type)));
|
||||||
|
|
||||||
|
/* If it is, we're done. */
|
||||||
|
R_SUCCEED_IF(entry_type == FsDirEntryType_Dir);
|
||||||
|
|
||||||
|
/* Otherwise, open as a file. */
|
||||||
|
FsFile file;
|
||||||
|
R_TRY(m_fs.OpenFile(obj->GetName(), FsOpenMode_Read, std::addressof(file)));
|
||||||
|
|
||||||
|
/* Ensure we maintain a clean state on exit. */
|
||||||
|
ON_SCOPE_EXIT { m_fs.CloseFile(std::addressof(file)); };
|
||||||
|
|
||||||
|
R_RETURN(m_fs.GetFileSize(std::addressof(file), out_size));
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Define helper for determining if the property should be included. */
|
||||||
|
const auto ShouldIncludeProperty = [&] (PtpObjectPropertyCode code) {
|
||||||
|
/* If all properties were requested, or it was the requested property, we should include the property. */
|
||||||
|
return property_code == -1 || code == property_code;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Begin writing the requested object properties. */
|
||||||
|
PtpDataBuilder db(m_buffers->usb_bulk_write_buffer, std::addressof(m_usb_server));
|
||||||
|
|
||||||
|
R_TRY(db.WriteVariableLengthData(m_request_header, [&] {
|
||||||
|
for (const auto obj_property : SupportedObjectProperties) {
|
||||||
|
if (!ShouldIncludeProperty(obj_property)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write the object handle. */
|
||||||
|
R_TRY(db.Add<u32>(object_id));
|
||||||
|
|
||||||
|
/* Write the property code. */
|
||||||
|
R_TRY(db.Add<u16>(obj_property));
|
||||||
|
|
||||||
|
/* Write the property value. */
|
||||||
|
switch (obj_property) {
|
||||||
|
case PtpObjectPropertyCode_PersistentUniqueObjectIdentifier:
|
||||||
|
{
|
||||||
|
R_TRY(db.Add(PtpDataTypeCode_U128));
|
||||||
|
R_TRY(db.Add<u128>(object_id));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PtpObjectPropertyCode_ObjectSize:
|
||||||
|
{
|
||||||
|
s64 size;
|
||||||
|
R_TRY(GetObjectSize(std::addressof(size)));
|
||||||
|
R_TRY(db.Add(PtpDataTypeCode_U64));
|
||||||
|
R_TRY(db.Add<u64>(size));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PtpObjectPropertyCode_StorageId:
|
||||||
|
{
|
||||||
|
R_TRY(db.Add(PtpDataTypeCode_U32));
|
||||||
|
R_TRY(db.Add(StorageId_SdmcFs));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PtpObjectPropertyCode_ParentObject:
|
||||||
|
{
|
||||||
|
R_TRY(db.Add(PtpDataTypeCode_U32));
|
||||||
|
R_TRY(db.Add(obj->GetParentId()));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PtpObjectPropertyCode_ObjectFormat:
|
||||||
|
{
|
||||||
|
FsDirEntryType entry_type;
|
||||||
|
R_TRY(GetObjectType(std::addressof(entry_type)));
|
||||||
|
R_TRY(db.Add(PtpDataTypeCode_U16));
|
||||||
|
R_TRY(db.Add(entry_type == FsDirEntryType_File ? PtpObjectFormatCode_Undefined : PtpObjectFormatCode_Association));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PtpObjectPropertyCode_ObjectFileName:
|
||||||
|
{
|
||||||
|
R_TRY(db.Add(PtpDataTypeCode_String));
|
||||||
|
R_TRY(db.AddString(std::strrchr(obj->GetName(), '/') + 1));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
HAZE_UNREACHABLE_DEFAULT_CASE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
R_SUCCEED();
|
||||||
|
}));
|
||||||
|
|
||||||
|
/* Write the success response. */
|
||||||
|
R_RETURN(this->WriteResponse(PtpResponseCode_Ok));
|
||||||
|
}
|
||||||
|
|
||||||
Result PtpResponder::SetObjectPropValue(PtpDataParser &rdp) {
|
Result PtpResponder::SetObjectPropValue(PtpDataParser &rdp) {
|
||||||
u32 object_id;
|
u32 object_id;
|
||||||
PtpObjectPropertyCode property_code;
|
PtpObjectPropertyCode property_code;
|
||||||
|
|
Loading…
Reference in a new issue