Index: src/OFZooArchiveEntry.h ================================================================== --- src/OFZooArchiveEntry.h +++ src/OFZooArchiveEntry.h @@ -17,10 +17,11 @@ #import "OFArchiveEntry.h" OF_ASSUME_NONNULL_BEGIN @class OFDate; +@class OFNumber; @class OFString; /** * @class OFZooArchiveEntry OFZooArchiveEntry.h ObjFW/OFZooArchiveEntry.h * @@ -38,10 +39,11 @@ uint16_t _CRC16; unsigned long long _uncompressedSize, _compressedSize; bool _deleted; OFString *_Nullable _fileComment; OFString *_fileName, *_Nullable _directoryName; + OFNumber *_Nullable _POSIXPermissions; OF_RESERVE_IVARS(OFZooArchiveEntry, 4) } /** * @brief The compression method of the entry. Index: src/OFZooArchiveEntry.m ================================================================== --- src/OFZooArchiveEntry.m +++ src/OFZooArchiveEntry.m @@ -16,10 +16,11 @@ #include "config.h" #import "OFZooArchiveEntry.h" #import "OFZooArchiveEntry+Private.h" #import "OFDate.h" +#import "OFNumber.h" #import "OFSeekableStream.h" #import "OFStream.h" #import "OFString.h" #import "OFInvalidFormatException.h" @@ -26,11 +27,11 @@ @implementation OFZooArchiveEntry @synthesize compressionMethod = _compressionMethod, CRC16 = _CRC16; @synthesize uncompressedSize = _uncompressedSize; @synthesize compressedSize = _compressedSize, deleted = _deleted; -@synthesize fileComment = _fileComment; +@synthesize fileComment = _fileComment, POSIXPermissions = _POSIXPermissions; - (instancetype)init { OF_INVALID_INIT_METHOD } @@ -113,10 +114,33 @@ _directoryName = [[stream readStringWithLength: directoryNameLength encoding: encoding] copy]; extraLength -= directoryNameLength; } + + if (extraLength >= 2) { + /* System ID */ + [stream readLittleEndianInt16]; + extraLength -= 2; + } + + if (extraLength >= 3) { + uint8_t attributes[3]; + + [stream readIntoBuffer: attributes + exactLength: 3]; + + if (attributes[2] & (1 << 6)) { + uint16_t mode = (attributes[0] | + (attributes[1] << 8)) & 0777; + + _POSIXPermissions = [[OFNumber alloc] + initWithUnsignedShort: mode]; + } + + extraLength -= 3; + } } else _fileName = [[OFString alloc] initWithCString: fileNameBuffer encoding: encoding]; @@ -139,10 +163,11 @@ - (void)dealloc { [_fileComment release]; [_fileName release]; [_directoryName release]; + [_POSIXPermissions release]; [super dealloc]; } - (id)copy Index: utils/ofarc/ZooArchive.m ================================================================== --- utils/ofarc/ZooArchive.m +++ utils/ofarc/ZooArchive.m @@ -30,10 +30,31 @@ #import "OFArc.h" #import "OFSetItemAttributesFailedException.h" static OFArc *app; + +static void +setPermissions(OFString *path, OFZooArchiveEntry *entry) +{ +#ifdef OF_FILE_MANAGER_SUPPORTS_PERMISSIONS + OFNumber *POSIXPermissions = entry.POSIXPermissions; + + if (POSIXPermissions == nil) + return; + + POSIXPermissions = [OFNumber numberWithUnsignedShort: + POSIXPermissions.unsignedShortValue & 0777]; + + OFFileAttributes attributes = [OFDictionary + dictionaryWithObject: POSIXPermissions + forKey: OFFilePOSIXPermissions]; + + [[OFFileManager defaultManager] setAttributes: attributes + ofItemAtPath: path]; +#endif +} static void setModificationDate(OFString *path, OFZooArchiveEntry *entry) { OFFileAttributes attributes = [OFDictionary @@ -151,10 +172,24 @@ [OFStdOut writeString: @"\t"]; [OFStdOut writeLine: OF_LOCALIZED( @"list_modification_date", @"Modification date: %[date]", @"date", modificationDate)]; + + if (entry.POSIXPermissions != nil) { + OFString *permissionsString = [OFString + stringWithFormat: @"%llo", + entry.POSIXPermissions + .unsignedLongLongValue]; + + [OFStdOut writeString: @"\t"]; + [OFStdOut writeLine: OF_LOCALIZED( + @"list_posix_permissions", + @"POSIX permissions: %[perm]", + @"perm", permissionsString)]; + } + [OFStdOut writeString: @"\t"]; [OFStdOut writeLine: OF_LOCALIZED( @"list_deleted", @"[" @" 'Deleted: '," @@ -224,10 +259,11 @@ if (![app shouldExtractFile: fileName outFileName: outFileName]) goto outer_loop_end; stream = [_archive streamForReadingCurrentEntry]; output = [OFFile fileWithPath: outFileName mode: @"w"]; + setPermissions(outFileName, entry); while (!stream.atEndOfStream) { ssize_t length = [app copyBlockFromStream: stream toStream: output fileName: fileName];