Index: src/OFArchiveEntry.h ================================================================== --- src/OFArchiveEntry.h +++ src/OFArchiveEntry.h @@ -12,13 +12,17 @@ * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #import "OFObject.h" +#import "OFString.h" OF_ASSUME_NONNULL_BEGIN +@class OFDate; +@class OFNumber; + /** * @protocol OFArchiveEntry OFArchiveEntry.h ObjFW/OFArchiveEntry.h * * @brief A class which represents an entry in an archive. */ @@ -36,10 +40,52 @@ /** * @brief The uncompressed size of the entry's file. */ @property (readonly, nonatomic) unsigned long long uncompressedSize; + +@optional +/** + * @brief The modification date of the file. + */ +@property (readonly, retain, nonatomic) OFDate *modificationDate; + +/** + * @brief The comment of the entry's file. + */ +@property OF_NULLABLE_PROPERTY (readonly, copy, nonatomic) + OFString *fileComment; + +/** + * @brief The POSIX permissions of the file. + */ +@property OF_NULLABLE_PROPERTY (readonly, retain, nonatomic) + OFNumber *POSIXPermissions; + +/** + * @brief The file owner's account ID. + */ +@property OF_NULLABLE_PROPERTY (readonly, retain, nonatomic) + OFNumber *ownerAccountID; + +/** + * @brief The file owner's group account ID. + */ +@property OF_NULLABLE_PROPERTY (readonly, retain, nonatomic) + OFNumber *groupOwnerAccountID; + +/** + * @brief The file owner's account name. + */ +@property OF_NULLABLE_PROPERTY (readonly, retain, nonatomic) + OFString *ownerAccountName; + +/** + * @brief The file owner's group account name. + */ +@property OF_NULLABLE_PROPERTY (readonly, retain, nonatomic) + OFString *groupOwnerAccountName; @end OF_ASSUME_NONNULL_END #import "OFMutableArchiveEntry.h" Index: src/OFLHAArchiveEntry.h ================================================================== --- src/OFLHAArchiveEntry.h +++ src/OFLHAArchiveEntry.h @@ -38,26 +38,23 @@ OFDate *_modificationDate; uint8_t _headerLevel; uint16_t _CRC16; uint8_t _operatingSystemIdentifier; OFString *_Nullable _fileComment; - OFNumber *_Nullable _mode, *_Nullable _UID, *_Nullable _GID; - OFString *_Nullable _owner, *_Nullable _group; + OFNumber *_Nullable _POSIXPermissions, *_Nullable _ownerAccountID; + OFNumber *_Nullable _groupOwnerAccountID; + OFString *_Nullable _ownerAccountName; + OFString *_Nullable _groupOwnerAccountName; OFMutableArray OF_GENERIC(OFData *) *_extensions; OF_RESERVE_IVARS(OFLHAArchiveEntry, 4) } /** * @brief The compression method of the entry. */ @property (readonly, copy, nonatomic) OFString *compressionMethod; -/** - * @brief The modification date of the file. - */ -@property (readonly, retain, nonatomic) OFDate *modificationDate; - /** * @brief The LHA level of the file. */ @property (readonly, nonatomic) uint8_t headerLevel; @@ -69,41 +66,10 @@ /** * @brief The operating system identifier of the file. */ @property (readonly, nonatomic) uint8_t operatingSystemIdentifier; -/** - * @brief The comment of the file. - */ -@property OF_NULLABLE_PROPERTY (readonly, copy, nonatomic) - OFString *fileComment; - -/** - * @brief The mode of the entry. - */ -@property OF_NULLABLE_PROPERTY (readonly, retain, nonatomic) OFNumber *mode; - -/** - * @brief The UID of the owner. - */ -@property OF_NULLABLE_PROPERTY (readonly, retain, nonatomic) OFNumber *UID; - -/** - * @brief The GID of the group. - */ -@property OF_NULLABLE_PROPERTY (readonly, retain, nonatomic) OFNumber *GID; - -/** - * @brief The owner of the file. - */ -@property OF_NULLABLE_PROPERTY (readonly, copy, nonatomic) OFString *owner; - -/** - * @brief The group of the file. - */ -@property OF_NULLABLE_PROPERTY (readonly, copy, nonatomic) OFString *group; - /** * @brief The LHA extensions of the file. */ @property (readonly, copy, nonatomic) OFArray OF_GENERIC(OFData *) *extensions; Index: src/OFLHAArchiveEntry.m ================================================================== --- src/OFLHAArchiveEntry.m +++ src/OFLHAArchiveEntry.m @@ -111,70 +111,73 @@ static void parsePermissionsExtension(OFLHAArchiveEntry *entry, OFData *extension, OFStringEncoding encoding) { - uint16_t mode; + uint16_t POSIXPermissions; if (extension.count != 3) @throw [OFInvalidFormatException exception]; - memcpy(&mode, (char *)extension.items + 1, 2); - mode = OFFromLittleEndian16(mode); + memcpy(&POSIXPermissions, (char *)extension.items + 1, 2); + POSIXPermissions = OFFromLittleEndian16(POSIXPermissions); - [entry->_mode release]; - entry->_mode = nil; + [entry->_POSIXPermissions release]; + entry->_POSIXPermissions = nil; - entry->_mode = [[OFNumber alloc] initWithUnsignedShort: mode]; + entry->_POSIXPermissions = + [[OFNumber alloc] initWithUnsignedShort: POSIXPermissions]; } static void parseGIDUIDExtension(OFLHAArchiveEntry *entry, OFData *extension, OFStringEncoding encoding) { - uint16_t UID, GID; + uint16_t ownerAccountID, groupOwnerAccountID; if (extension.count != 5) @throw [OFInvalidFormatException exception]; - memcpy(&GID, (char *)extension.items + 1, 2); - GID = OFFromLittleEndian16(GID); - - memcpy(&UID, (char *)extension.items + 3, 2); - UID = OFFromLittleEndian16(UID); - - [entry->_GID release]; - entry->_GID = nil; - - [entry->_UID release]; - entry->_UID = nil; - - entry->_GID = [[OFNumber alloc] initWithUnsignedShort: GID]; - entry->_UID = [[OFNumber alloc] initWithUnsignedShort: UID]; + memcpy(&groupOwnerAccountID, (char *)extension.items + 1, 2); + groupOwnerAccountID = OFFromLittleEndian16(groupOwnerAccountID); + + memcpy(&ownerAccountID, (char *)extension.items + 3, 2); + ownerAccountID = OFFromLittleEndian16(ownerAccountID); + + [entry->_groupOwnerAccountID release]; + entry->_groupOwnerAccountID = nil; + + [entry->_ownerAccountID release]; + entry->_ownerAccountID = nil; + + entry->_groupOwnerAccountID = + [[OFNumber alloc] initWithUnsignedShort: groupOwnerAccountID]; + entry->_ownerAccountID = + [[OFNumber alloc] initWithUnsignedShort: ownerAccountID]; } static void parseGroupExtension(OFLHAArchiveEntry *entry, OFData *extension, OFStringEncoding encoding) { - [entry->_group release]; - entry->_group = nil; + [entry->_groupOwnerAccountName release]; + entry->_groupOwnerAccountName = nil; - entry->_group = [[OFString alloc] + entry->_groupOwnerAccountName = [[OFString alloc] initWithCString: (char *)extension.items + 1 encoding: encoding length: extension.count - 1]; } static void parseOwnerExtension(OFLHAArchiveEntry *entry, OFData *extension, OFStringEncoding encoding) { - [entry->_owner release]; - entry->_owner = nil; + [entry->_ownerAccountName release]; + entry->_ownerAccountName = nil; - entry->_owner = [[OFString alloc] + entry->_ownerAccountName = [[OFString alloc] initWithCString: (char *)extension.items + 1 encoding: encoding length: extension.count - 1]; } @@ -416,15 +419,15 @@ [_compressionMethod release]; [_fileName release]; [_directoryName release]; [_modificationDate release]; [_fileComment release]; - [_mode release]; - [_UID release]; - [_GID release]; - [_owner release]; - [_group release]; + [_POSIXPermissions release]; + [_ownerAccountID release]; + [_groupOwnerAccountID release]; + [_ownerAccountName release]; + [_groupOwnerAccountName release]; [_extensions release]; [super dealloc]; } @@ -452,15 +455,15 @@ copy->_modificationDate = [_modificationDate copy]; copy->_headerLevel = _headerLevel; copy->_CRC16 = _CRC16; copy->_operatingSystemIdentifier = _operatingSystemIdentifier; copy->_fileComment = [_fileComment copy]; - copy->_mode = [_mode retain]; - copy->_UID = [_UID retain]; - copy->_GID = [_GID retain]; - copy->_owner = [_owner copy]; - copy->_group = [_group copy]; + copy->_POSIXPermissions = [_POSIXPermissions retain]; + copy->_ownerAccountID = [_ownerAccountID retain]; + copy->_groupOwnerAccountID = [_groupOwnerAccountID retain]; + copy->_ownerAccountName = [_ownerAccountName copy]; + copy->_groupOwnerAccountName = [_groupOwnerAccountName copy]; copy->_extensions = [_extensions copy]; } @catch (id e) { [copy release]; @throw e; } @@ -514,33 +517,33 @@ - (OFString *)fileComment { return _fileComment; } -- (OFNumber *)mode -{ - return _mode; -} - -- (OFNumber *)UID -{ - return _UID; -} - -- (OFNumber *)GID -{ - return _GID; -} - -- (OFString *)owner -{ - return _owner; -} - -- (OFString *)group -{ - return _group; +- (OFNumber *)POSIXPermissions +{ + return _POSIXPermissions; +} + +- (OFNumber *)ownerAccountID +{ + return _ownerAccountID; +} + +- (OFNumber *)groupOwnerAccountID +{ + return _groupOwnerAccountID; +} + +- (OFString *)ownerAccountName +{ + return _ownerAccountName; +} + +- (OFString *)groupOwnerAccountName +{ + return _groupOwnerAccountName; } - (OFArray OF_GENERIC(OFData *) *)extensions { return _extensions; @@ -629,60 +632,64 @@ [data addItem: "\x3F"]; [data addItems: [_fileComment cStringWithEncoding: encoding] count: fileCommentLength]; } - if (_mode != nil) { + if (_POSIXPermissions != nil) { tmp16 = OFToLittleEndian16(5); [data addItems: &tmp16 count: sizeof(tmp16)]; [data addItem: "\x50"]; - tmp16 = OFToLittleEndian16(_mode.unsignedShortValue); + tmp16 = + OFToLittleEndian16(_POSIXPermissions.unsignedShortValue); [data addItems: &tmp16 count: sizeof(tmp16)]; } - if (_UID != nil || _GID != nil) { - if (_UID == nil || _GID == nil) + if (_ownerAccountID != nil || _groupOwnerAccountID != nil) { + if (_ownerAccountID == nil || _groupOwnerAccountID == nil) @throw [OFInvalidArgumentException exception]; tmp16 = OFToLittleEndian16(7); [data addItems: &tmp16 count: sizeof(tmp16)]; [data addItem: "\x51"]; - tmp16 = OFToLittleEndian16(_GID.unsignedShortValue); + tmp16 = OFToLittleEndian16( + _groupOwnerAccountID.unsignedShortValue); [data addItems: &tmp16 count: sizeof(tmp16)]; - tmp16 = OFToLittleEndian16(_UID.unsignedShortValue); + tmp16 = OFToLittleEndian16(_ownerAccountID.unsignedShortValue); [data addItems: &tmp16 count: sizeof(tmp16)]; } - if (_group != nil) { - size_t groupLength = - [_group cStringLengthWithEncoding: encoding]; + if (_groupOwnerAccountName != nil) { + size_t length = [_groupOwnerAccountName + cStringLengthWithEncoding: encoding]; - if (groupLength > UINT16_MAX - 3) + if (length > UINT16_MAX - 3) @throw [OFOutOfRangeException exception]; - tmp16 = OFToLittleEndian16((uint16_t)groupLength + 3); + tmp16 = OFToLittleEndian16((uint16_t)length + 3); [data addItems: &tmp16 count: sizeof(tmp16)]; [data addItem: "\x52"]; - [data addItems: [_group cStringWithEncoding: encoding] - count: groupLength]; + [data addItems: [_groupOwnerAccountName + cStringWithEncoding: encoding] + count: length]; } - if (_owner != nil) { - size_t ownerLength = - [_owner cStringLengthWithEncoding: encoding]; + if (_ownerAccountName != nil) { + size_t length = + [_ownerAccountName cStringLengthWithEncoding: encoding]; - if (ownerLength > UINT16_MAX - 3) + if (length > UINT16_MAX - 3) @throw [OFOutOfRangeException exception]; - tmp16 = OFToLittleEndian16((uint16_t)ownerLength + 3); + tmp16 = OFToLittleEndian16((uint16_t)length + 3); [data addItems: &tmp16 count: sizeof(tmp16)]; [data addItem: "\x53"]; - [data addItems: [_owner cStringWithEncoding: encoding] - count: ownerLength]; + [data addItems: [_ownerAccountName + cStringWithEncoding: encoding] + count: length]; } for (OFData *extension in _extensions) { size_t extensionLength = extension.count; @@ -719,16 +726,21 @@ } - (OFString *)description { void *pool = objc_autoreleasePoolPush(); - OFString *mode = (_mode == nil ? nil - : [OFString stringWithFormat: @"%ho", _mode.unsignedShortValue]); + OFString *POSIXPermissions = nil; OFString *extensions = [_extensions.description stringByReplacingOccurrencesOfString: @"\n" withString: @"\n\t"]; - OFString *ret = [OFString stringWithFormat: + OFString *ret; + + if (_POSIXPermissions != nil) + POSIXPermissions = [OFString stringWithFormat: @"%ho", + _POSIXPermissions.unsignedShortValue]; + + ret = [OFString stringWithFormat: @"<%@:\n" @"\tFile name = %@\n" @"\tCompression method = %@\n" @"\tCompressed size = %llu\n" @"\tUncompressed size = %llu\n" @@ -735,24 +747,25 @@ @"\tModification date = %@\n" @"\tHeader level = %u\n" @"\tCRC16 = %04" @PRIX16 @"\n" @"\tOperating system identifier = %c\n" @"\tComment = %@\n" - @"\tMode = %@\n" - @"\tUID = %@\n" - @"\tGID = %@\n" - @"\tOwner = %@\n" - @"\tGroup = %@\n" + @"\tPOSIX permissions = %@\n" + @"\tOwner account ID = %@\n" + @"\tGroup owner account ID = %@\n" + @"\tOwner account name = %@\n" + @"\tGroup owner accounut name = %@\n" @"\tExtensions: %@" @">", self.class, self.fileName, _compressionMethod, _compressedSize, _uncompressedSize, _modificationDate, _headerLevel, _CRC16, - _operatingSystemIdentifier, _fileComment, mode, _UID, _GID, _owner, - _group, extensions]; + _operatingSystemIdentifier, _fileComment, POSIXPermissions, + _ownerAccountID, _groupOwnerAccountID, _ownerAccountName, + _groupOwnerAccountName, extensions]; [ret retain]; objc_autoreleasePoolPop(pool); return [ret autorelease]; } @end Index: src/OFMutableArchiveEntry.h ================================================================== --- src/OFMutableArchiveEntry.h +++ src/OFMutableArchiveEntry.h @@ -11,11 +11,11 @@ * Public License, either version 2 or 3, which can be found in the file * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ -#import "OFObject.h" +#import "OFArchiveEntry.h" OF_ASSUME_NONNULL_BEGIN /** * @protocol OFMutableArchiveEntry \ @@ -37,10 +37,52 @@ /** * @brief The uncompressed size of the entry's file. */ @property (readwrite, nonatomic) unsigned long long uncompressedSize; + +@optional +/** + * @brief The modification date of the file. + */ +@property (readwrite, retain, nonatomic) OFDate *modificationDate; + +/** + * @brief The comment of the entry's file. + */ +@property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic) + OFString *fileComment; + +/** + * @brief The POSIX permissions of the file. + */ +@property OF_NULLABLE_PROPERTY (readwrite, retain, nonatomic) + OFNumber *POSIXPermissions; + +/** + * @brief The file owner's account ID. + */ +@property OF_NULLABLE_PROPERTY (readwrite, retain, nonatomic) + OFNumber *ownerAccountID; + +/** + * @brief The file owner's group account ID. + */ +@property OF_NULLABLE_PROPERTY (readwrite, retain, nonatomic) + OFNumber *groupOwnerAccountID; + +/** + * @brief The file owner's account name. + */ +@property OF_NULLABLE_PROPERTY (readwrite, retain, nonatomic) + OFString *ownerAccountName; + +/** + * @brief The file owner's group account name. + */ +@property OF_NULLABLE_PROPERTY (readwrite, retain, nonatomic) + OFString *groupOwnerAccountName; @end OF_ASSUME_NONNULL_END #import "OFMutableArchiveEntry.h" Index: src/OFMutableLHAArchiveEntry.h ================================================================== --- src/OFMutableLHAArchiveEntry.h +++ src/OFMutableLHAArchiveEntry.h @@ -32,15 +32,10 @@ /** * @brief The compression method of the entry. */ @property (readwrite, copy, nonatomic) OFString *compressionMethod; -/** - * @brief The modification date of the file. - */ -@property (readwrite, retain, nonatomic) OFDate *modificationDate; - /** * @brief The LHA level of the file. */ @property (readwrite, nonatomic) uint8_t headerLevel; @@ -52,41 +47,10 @@ /** * @brief The operating system identifier of the file. */ @property (readwrite, nonatomic) uint8_t operatingSystemIdentifier; -/** - * @brief The comment of the file. - */ -@property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic) - OFString *fileComment; - -/** - * @brief The mode of the entry. - */ -@property OF_NULLABLE_PROPERTY (readwrite, retain, nonatomic) OFNumber *mode; - -/** - * @brief The UID of the owner. - */ -@property OF_NULLABLE_PROPERTY (readwrite, retain, nonatomic) OFNumber *UID; - -/** - * @brief The GID of the group. - */ -@property OF_NULLABLE_PROPERTY (readwrite, retain, nonatomic) OFNumber *GID; - -/** - * @brief The owner of the file. - */ -@property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic) OFString *owner; - -/** - * @brief The group of the file. - */ -@property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic) OFString *group; - /** * @brief The LHA extensions of the file. */ @property (readwrite, copy, nonatomic) OFArray OF_GENERIC(OFData *) *extensions; Index: src/OFMutableLHAArchiveEntry.m ================================================================== --- src/OFMutableLHAArchiveEntry.m +++ src/OFMutableLHAArchiveEntry.m @@ -25,11 +25,12 @@ #import "OFString.h" @implementation OFMutableLHAArchiveEntry @dynamic fileName, compressionMethod, compressedSize, uncompressedSize; @dynamic modificationDate, headerLevel, CRC16, operatingSystemIdentifier; -@dynamic fileComment, mode, UID, GID, owner, group, extensions; +@dynamic fileComment, POSIXPermissions, ownerAccountID, groupOwnerAccountID; +@dynamic ownerAccountName, groupOwnerAccountName, extensions; + (instancetype)entryWithFileName: (OFString *)fileName { return [[[self alloc] initWithFileName: fileName] autorelease]; } @@ -111,42 +112,42 @@ OFString *old = _fileComment; _fileComment = [fileComment copy]; [old release]; } -- (void)setMode: (OFNumber *)mode -{ - OFNumber *old = _mode; - _mode = [mode retain]; - [old release]; -} - -- (void)setUID: (OFNumber *)UID -{ - OFNumber *old = _UID; - _UID = [UID retain]; - [old release]; -} - -- (void)setGID: (OFNumber *)GID -{ - OFNumber *old = _GID; - _GID = [GID retain]; - [old release]; -} - -- (void)setOwner: (OFString *)owner -{ - OFString *old = _owner; - _owner = [owner copy]; - [old release]; -} - -- (void)setGroup: (OFString *)group -{ - OFString *old = _group; - _group = [group copy]; +- (void)setPOSIXPermissions: (OFNumber *)POSIXPermissions +{ + OFNumber *old = _POSIXPermissions; + _POSIXPermissions = [POSIXPermissions retain]; + [old release]; +} + +- (void)setOwnerAccountID: (OFNumber *)ownerAccountID +{ + OFNumber *old = _ownerAccountID; + _ownerAccountID = [ownerAccountID retain]; + [old release]; +} + +- (void)setGroupOwnerAccountID: (OFNumber *)groupOwnerAccountID +{ + OFNumber *old = _groupOwnerAccountID; + _groupOwnerAccountID = [groupOwnerAccountID retain]; + [old release]; +} + +- (void)setOwnerAccounutName: (OFString *)ownerAccountName +{ + OFString *old = _ownerAccountName; + _ownerAccountName = [ownerAccountName copy]; + [old release]; +} + +- (void)setGroupOwnerAccountName: (OFString *)groupOwnerAccountName +{ + OFString *old = _groupOwnerAccountName; + _groupOwnerAccountName = [groupOwnerAccountName copy]; [old release]; } - (void)setExtensions: (OFArray OF_GENERIC(OFData *) *)extensions { Index: src/OFMutableTarArchiveEntry.h ================================================================== --- src/OFMutableTarArchiveEntry.h +++ src/OFMutableTarArchiveEntry.h @@ -27,30 +27,10 @@ @interface OFMutableTarArchiveEntry: OFTarArchiveEntry { OF_RESERVE_IVARS(OFMutableTarArchiveEntry, 4) } -/** - * @brief The mode of the entry. - */ -@property (readwrite, retain, nonatomic) OFNumber *mode; - -/** - * @brief The UID of the owner. - */ -@property (readwrite, retain, nonatomic) OFNumber *UID; - -/** - * @brief The GID of the group. - */ -@property (readwrite, retain, nonatomic) OFNumber *GID; - -/** - * @brief The date of the last modification of the file. - */ -@property (readwrite, retain, nonatomic) OFDate *modificationDate; - /** * @brief The type of the archive entry. * * See @ref OFTarArchiveEntryType. */ @@ -60,20 +40,10 @@ * @brief The file name of the target (for a hard link or symbolic link). */ @property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic) OFString *targetFileName; -/** - * @brief The owner of the file. - */ -@property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic) OFString *owner; - -/** - * @brief The group of the file. - */ -@property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic) OFString *group; - /** * @brief The device major (if the file is a device). */ @property (readwrite, nonatomic) unsigned long deviceMajor; Index: src/OFMutableTarArchiveEntry.m ================================================================== --- src/OFMutableTarArchiveEntry.m +++ src/OFMutableTarArchiveEntry.m @@ -20,12 +20,13 @@ #import "OFDate.h" #import "OFNumber.h" #import "OFString.h" @implementation OFMutableTarArchiveEntry -@dynamic fileName, mode, UID, GID, compressedSize, uncompressedSize; -@dynamic modificationDate, type, targetFileName, owner, group, deviceMajor; +@dynamic fileName, POSIXPermissions, ownerAccountID, groupOwnerAccountID; +@dynamic compressedSize, uncompressedSize, modificationDate, type; +@dynamic targetFileName, ownerAccountName, groupOwnerAccountName, deviceMajor; @dynamic deviceMinor; + (instancetype)entryWithFileName: (OFString *)fileName { return [[[self alloc] initWithFileName: fileName] autorelease]; @@ -59,28 +60,28 @@ OFString *old = _fileName; _fileName = [fileName copy]; [old release]; } -- (void)setMode: (OFNumber *)mode +- (void)setPOSIXPermissions: (OFNumber *)POSIXPermissions { - OFNumber *old = _mode; - _mode = [mode retain]; + OFNumber *old = _POSIXPermissions; + _POSIXPermissions = [POSIXPermissions retain]; [old release]; } -- (void)setUID: (OFNumber *)UID +- (void)setOwnerAccountID: (OFNumber *)ownerAccountID { - OFNumber *old = _UID; - _UID = [UID retain]; + OFNumber *old = _ownerAccountID; + _ownerAccountID = [ownerAccountID retain]; [old release]; } -- (void)setGID: (OFNumber *)GID +- (void)setGroupOwnerAccountID: (OFNumber *)groupOwnerAccountID { - OFNumber *old = _GID; - _GID = [GID retain]; + OFNumber *old = _groupOwnerAccountID; + _groupOwnerAccountID = [groupOwnerAccountID retain]; [old release]; } - (void)setCompressedSize: (unsigned long long)compressedSize { @@ -109,21 +110,21 @@ OFString *old = _targetFileName; _targetFileName = [targetFileName copy]; [old release]; } -- (void)setOwner: (OFString *)owner +- (void)setOwnerAccountName: (OFString *)ownerAccountName { - OFString *old = _owner; - _owner = [owner copy]; + OFString *old = _ownerAccountName; + _ownerAccountName = [ownerAccountName copy]; [old release]; } -- (void)setGroup: (OFString *)group +- (void)setGroupOwnerAccountName: (OFString *)groupOwnerAccountName { - OFString *old = _group; - _group = [group copy]; + OFString *old = _groupOwnerAccountName; + _groupOwnerAccountName = [groupOwnerAccountName copy]; [old release]; } - (void)setDeviceMajor: (unsigned long)deviceMajor { Index: src/OFMutableZIPArchiveEntry.h ================================================================== --- src/OFMutableZIPArchiveEntry.h +++ src/OFMutableZIPArchiveEntry.h @@ -28,16 +28,10 @@ @interface OFMutableZIPArchiveEntry: OFZIPArchiveEntry { OF_RESERVE_IVARS(OFMutableZIPArchiveEntry, 4) } -/** - * @brief The comment of the entry's file. - */ -@property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic) - OFString *fileComment; - /** * @brief The extra field of the entry. * * The item size *must* be 1! */ @@ -61,17 +55,10 @@ * See @ref OFZIPArchiveEntryAttributeCompatibility. */ @property (readwrite, nonatomic) OFZIPArchiveEntryAttributeCompatibility minVersionNeeded; -/** - * @brief The last modification date of the entry's file. - * - * @note Due to limitations of the ZIP format, this has only 2 second precision. - */ -@property (readwrite, retain, nonatomic) OFDate *modificationDate; - /** * @brief The compression method of the entry. * * Supported values are: * Value | Description Index: src/OFTarArchiveEntry.h ================================================================== --- src/OFTarArchiveEntry.h +++ src/OFTarArchiveEntry.h @@ -52,40 +52,21 @@ */ @interface OFTarArchiveEntry: OFObject { OFString *_fileName; - OFNumber *_mode, *_UID, *_GID; + OFNumber *_POSIXPermissions, *_ownerAccountID, *_groupOwnerAccountID; unsigned long long _compressedSize, _uncompressedSize; OFDate *_modificationDate; OFTarArchiveEntryType _type; OFString *_Nullable _targetFileName; - OFString *_Nullable _owner, *_Nullable _group; + OFString *_Nullable _ownerAccountName; + OFString *_Nullable _groupOwnerAccountName; unsigned long _deviceMajor, _deviceMinor; OF_RESERVE_IVARS(OFTarArchiveEntry, 4) } -/** - * @brief The mode of the entry. - */ -@property (readonly, retain, nonatomic) OFNumber *mode; - -/** - * @brief The UID of the owner. - */ -@property (readonly, retain, nonatomic) OFNumber *UID; - -/** - * @brief The GID of the group. - */ -@property (readonly, retain, nonatomic) OFNumber *GID; - -/** - * @brief The date of the last modification of the file. - */ -@property (readonly, retain, nonatomic) OFDate *modificationDate; - /** * @brief The type of the archive entry. * * See @ref OFTarArchiveEntryType. */ @@ -95,20 +76,10 @@ * @brief The file name of the target (for a hard link or symbolic link). */ @property OF_NULLABLE_PROPERTY (readonly, copy, nonatomic) OFString *targetFileName; -/** - * @brief The owner of the file. - */ -@property OF_NULLABLE_PROPERTY (readonly, copy, nonatomic) OFString *owner; - -/** - * @brief The group of the file. - */ -@property OF_NULLABLE_PROPERTY (readonly, copy, nonatomic) OFString *group; - /** * @brief The device major (if the file is a device). */ @property (readonly, nonatomic) unsigned long deviceMajor; Index: src/OFTarArchiveEntry.m ================================================================== --- src/OFTarArchiveEntry.m +++ src/OFTarArchiveEntry.m @@ -84,11 +84,12 @@ { self = [super init]; @try { _type = OFTarArchiveEntryTypeFile; - _mode = [[OFNumber alloc] initWithUnsignedShort: 0644]; + _POSIXPermissions = + [[OFNumber alloc] initWithUnsignedShort: 0644]; } @catch (id e) { [self release]; @throw e; } @@ -103,15 +104,16 @@ @try { void *pool = objc_autoreleasePoolPush(); OFString *targetFileName; _fileName = [stringFromBuffer(header, 100, encoding) copy]; - _mode = [[OFNumber alloc] initWithUnsignedLongLong: + _POSIXPermissions = [[OFNumber alloc] initWithUnsignedLongLong: octalValueFromBuffer(header + 100, 8, ULONG_MAX)]; - _UID = [[OFNumber alloc] initWithUnsignedLongLong: + _ownerAccountID = [[OFNumber alloc] initWithUnsignedLongLong: octalValueFromBuffer(header + 108, 8, ULONG_MAX)]; - _GID = [[OFNumber alloc] initWithUnsignedLongLong: + _groupOwnerAccountID = [[OFNumber alloc] + initWithUnsignedLongLong: octalValueFromBuffer(header + 116, 8, ULONG_MAX)]; _uncompressedSize = (unsigned long long)octalValueFromBuffer( header + 124, 12, ULLONG_MAX); _compressedSize = _uncompressedSize + (512 - _uncompressedSize % 512); @@ -129,14 +131,14 @@ _type = OFTarArchiveEntryTypeFile; if (memcmp(header + 257, "ustar\0" "00", 8) == 0) { OFString *prefix; - _owner = [stringFromBuffer(header + 265, 32, encoding) - copy]; - _group = [stringFromBuffer(header + 297, 32, encoding) - copy]; + _ownerAccountName = + [stringFromBuffer(header + 265, 32, encoding) copy]; + _groupOwnerAccountName = [stringFromBuffer(header + 297, + 32, encoding) copy]; _deviceMajor = (unsigned long)octalValueFromBuffer( header + 329, 8, ULONG_MAX); _deviceMinor = (unsigned long)octalValueFromBuffer( header + 337, 8, ULONG_MAX); @@ -161,17 +163,17 @@ } - (void)dealloc { [_fileName release]; - [_mode release]; - [_UID release]; - [_GID release]; + [_POSIXPermissions release]; + [_ownerAccountID release]; + [_groupOwnerAccountID release]; [_modificationDate release]; [_targetFileName release]; - [_owner release]; - [_group release]; + [_ownerAccountName release]; + [_groupOwnerAccountName release]; [super dealloc]; } - (id)copy @@ -183,18 +185,20 @@ { OFTarArchiveEntry *copy = [[OFMutableTarArchiveEntry alloc] initWithFileName: _fileName]; @try { - copy->_mode = _mode; + copy->_POSIXPermissions = [_POSIXPermissions retain]; + copy->_ownerAccountID = [_ownerAccountID retain]; + copy->_groupOwnerAccountID = [_groupOwnerAccountID retain]; copy->_compressedSize = _compressedSize; copy->_uncompressedSize = _uncompressedSize; copy->_modificationDate = [_modificationDate copy]; copy->_type = _type; copy->_targetFileName = [_targetFileName copy]; - copy->_owner = [_owner copy]; - copy->_group = [_group copy]; + copy->_ownerAccountName = [_ownerAccountName copy]; + copy->_groupOwnerAccountName = [_groupOwnerAccountName copy]; copy->_deviceMajor = _deviceMajor; copy->_deviceMinor = _deviceMinor; } @catch (id e) { [copy release]; @throw e; @@ -206,23 +210,23 @@ - (OFString *)fileName { return _fileName; } -- (OFNumber *)mode +- (OFNumber *)POSIXPermissions { - return _mode; + return _POSIXPermissions; } -- (OFNumber *)UID +- (OFNumber *)ownerAccountID { - return _UID; + return _ownerAccountID; } -- (OFNumber *)GID +- (OFNumber *)groupOwnerAccountID { - return _GID; + return _groupOwnerAccountID; } - (unsigned long long)compressedSize { return _compressedSize; @@ -246,18 +250,18 @@ - (OFString *)targetFileName { return _targetFileName; } -- (OFString *)owner +- (OFString *)ownerAccountName { - return _owner; + return _ownerAccountName; } -- (OFString *)group +- (OFString *)groupOwnerAccountName { - return _group; + return _groupOwnerAccountName; } - (unsigned long)deviceMajor { return _deviceMajor; @@ -269,28 +273,36 @@ } - (OFString *)description { void *pool = objc_autoreleasePoolPush(); - OFString *ret = [OFString stringWithFormat: @"<%@:\n" + OFString *POSIXPermissions = nil, *ret; + + if (_POSIXPermissions != nil) + POSIXPermissions = [OFString stringWithFormat: @"%ho", + _POSIXPermissions.unsignedShortValue]; + + ret = [OFString stringWithFormat: @"<%@:\n" @"\tFile name = %@\n" - @"\tMode = %06o\n" - @"\tUID = %u\n" - @"\tGID = %u\n" + @"\tPOSIX permissions = %@\n" + @"\tOwner account ID = %@\n" + @"\tGroup owner account ID = %@\n" @"\tCompressed size = %llu\n" @"\tUncompressed size = %llu\n" @"\tModification date = %@\n" @"\tType = %u\n" @"\tTarget file name = %@\n" - @"\tOwner = %@\n" - @"\tGroup = %@\n" + @"\tOwner account name = %@\n" + @"\tGroup owner account name = %@\n" @"\tDevice major = %" PRIu32 @"\n" @"\tDevice minor = %" PRIu32 @"\n" @">", - self.class, _fileName, _mode, _UID, _GID, _compressedSize, - _uncompressedSize, _modificationDate, _type, _targetFileName, - _owner, _group, _deviceMajor, _deviceMinor]; + self.class, _fileName, POSIXPermissions, _ownerAccountID, + _groupOwnerAccountID, _compressedSize, _uncompressedSize, + _modificationDate, _type, _targetFileName, + _ownerAccountName, _groupOwnerAccountName, _deviceMajor, + _deviceMinor]; [ret retain]; objc_autoreleasePoolPop(pool); @@ -304,18 +316,18 @@ unsigned long long modificationDate; uint16_t checksum = 0; stringToBuffer(buffer, _fileName, 100, encoding); stringToBuffer(buffer + 100, - [OFString stringWithFormat: @"%06" PRIo16 " ", _mode], 8, - OFStringEncodingASCII); + [OFString stringWithFormat: @"%06o ", + _POSIXPermissions.unsignedShortValue], 8, OFStringEncodingASCII); stringToBuffer(buffer + 108, - [OFString stringWithFormat: @"%06" PRIo16 " ", _UID], 8, - OFStringEncodingASCII); + [OFString stringWithFormat: @"%06o ", + _ownerAccountID.unsignedShortValue], 8, OFStringEncodingASCII); stringToBuffer(buffer + 116, - [OFString stringWithFormat: @"%06" PRIo16 " ", _GID], 8, - OFStringEncodingASCII); + [OFString stringWithFormat: @"%06o ", + _groupOwnerAccountID.unsignedShortValue], 8, OFStringEncodingASCII); stringToBuffer(buffer + 124, [OFString stringWithFormat: @"%011llo ", _uncompressedSize], 12, OFStringEncodingASCII); modificationDate = _modificationDate.timeIntervalSince1970; stringToBuffer(buffer + 136, @@ -331,12 +343,12 @@ buffer[156] = _type; stringToBuffer(buffer + 157, _targetFileName, 100, encoding); /* ustar */ memcpy(buffer + 257, "ustar\0" "00", 8); - stringToBuffer(buffer + 265, _owner, 32, encoding); - stringToBuffer(buffer + 297, _group, 32, encoding); + stringToBuffer(buffer + 265, _ownerAccountName, 32, encoding); + stringToBuffer(buffer + 297, _groupOwnerAccountName, 32, encoding); stringToBuffer(buffer + 329, [OFString stringWithFormat: @"%06" PRIo32 " ", _deviceMajor], 8, OFStringEncodingASCII); stringToBuffer(buffer + 337, [OFString stringWithFormat: @"%06" PRIo32 " ", _deviceMinor], 8, Index: src/OFZIPArchiveEntry.h ================================================================== --- src/OFZIPArchiveEntry.h +++ src/OFZIPArchiveEntry.h @@ -119,16 +119,10 @@ uint32_t _versionSpecificAttributes; int64_t _localFileHeaderOffset; OF_RESERVE_IVARS(OFZIPArchiveEntry, 4) } -/** - * @brief The comment of the entry's file. - */ -@property OF_NULLABLE_PROPERTY (readonly, copy, nonatomic) - OFString *fileComment; - /** * @brief The extra field of the entry. * * The item size *must* be 1! */ @@ -152,17 +146,10 @@ * See @ref OFZIPArchiveEntryAttributeCompatibility. */ @property (readonly, nonatomic) OFZIPArchiveEntryAttributeCompatibility minVersionNeeded; -/** - * @brief The last modification date of the entry's file. - * - * @note Due to limitations of the ZIP format, this has only 2 second precision. - */ -@property (readonly, retain, nonatomic) OFDate *modificationDate; - /** * @brief The compression method of the entry. * * Supported values are: * Value | Description Index: utils/ofarc/LHAArchive.m ================================================================== --- utils/ofarc/LHAArchive.m +++ utils/ofarc/LHAArchive.m @@ -38,20 +38,20 @@ static void setPermissions(OFString *path, OFLHAArchiveEntry *entry) { #ifdef OF_FILE_MANAGER_SUPPORTS_PERMISSIONS - OFNumber *mode = entry.mode; + OFNumber *POSIXPermissions = entry.POSIXPermissions; - if (mode == nil) + if (POSIXPermissions == nil) return; - mode = [OFNumber numberWithUnsignedShort: - mode.unsignedShortValue & 0777]; + POSIXPermissions = [OFNumber numberWithUnsignedShort: + POSIXPermissions.unsignedShortValue & 0777]; OFFileAttributes attributes = [OFDictionary - dictionaryWithObject: mode + dictionaryWithObject: POSIXPermissions forKey: OFFilePOSIXPermissions]; [[OFFileManager defaultManager] setAttributes: attributes ofItemAtPath: path]; #endif @@ -164,45 +164,48 @@ [OFStdOut writeLine: OF_LOCALIZED( @"list_modification_date", @"Modification date: %[date]", @"date", modificationDate)]; - if (entry.mode != nil) { - OFString *modeString = [OFString - stringWithFormat: - @"%ho", entry.mode.unsignedShortValue]; - - [OFStdOut writeString: @"\t"]; - [OFStdOut writeLine: OF_LOCALIZED(@"list_mode", - @"Mode: %[mode]", - @"mode", modeString)]; - } - if (entry.UID != nil) { - [OFStdOut writeString: @"\t"]; - [OFStdOut writeLine: OF_LOCALIZED(@"list_uid", - @"UID: %[uid]", - @"uid", entry.UID)]; - } - if (entry.GID != nil) { + 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)]; + } + if (entry.ownerAccountID != nil) { + [OFStdOut writeString: @"\t"]; + [OFStdOut writeLine: OF_LOCALIZED( + @"list_owner_account_id", + @"Owner account ID: %[id]", + @"id", entry.ownerAccountID)]; + } + if (entry.groupOwnerAccountID != nil) { [OFStdOut writeString: @"\t"]; [OFStdOut writeLine: OF_LOCALIZED(@"list_gid", - @"GID: %[gid]", - @"gid", entry.GID)]; - } - if (entry.owner != nil) { - [OFStdOut writeString: @"\t"]; - [OFStdOut writeLine: OF_LOCALIZED( - @"list_owner", - @"Owner: %[owner]", - @"owner", entry.owner)]; - } - if (entry.group != nil) { - [OFStdOut writeString: @"\t"]; - [OFStdOut writeLine: OF_LOCALIZED( - @"list_group", - @"Group: %[group]", - @"group", entry.group)]; + @"Group owner account ID: %[id]", + @"id", entry.groupOwnerAccountID)]; + } + if (entry.ownerAccountName != nil) { + [OFStdOut writeString: @"\t"]; + [OFStdOut writeLine: OF_LOCALIZED( + @"list_owner_account_name", + @"Owner account name: %[name]", + @"name", entry.ownerAccountName)]; + } + if (entry.groupOwnerAccountName != nil) { + [OFStdOut writeString: @"\t"]; + [OFStdOut writeLine: OF_LOCALIZED( + @"list_group_owner_account_name", + @"Group: %[name]", + @"name", entry.groupOwnerAccountName)]; } if (app->_outputLevel >= 2) { OFString *headerLevel = [OFString stringWithFormat: @"%" PRIu8, @@ -442,22 +445,24 @@ attributes = [fileManager attributesOfItemAtPath: fileName]; type = attributes.fileType; entry = [OFMutableLHAArchiveEntry entryWithFileName: fileName]; #ifdef OF_FILE_MANAGER_SUPPORTS_PERMISSIONS - entry.mode = [OFNumber numberWithUnsignedLong: - attributes.filePOSIXPermissions]; + entry.POSIXPermissions = + [attributes objectForKey: OFFilePOSIXPermissions]; #endif entry.modificationDate = attributes.fileModificationDate; #ifdef OF_FILE_MANAGER_SUPPORTS_OWNER - entry.UID = [OFNumber numberWithUnsignedLong: - attributes.fileOwnerAccountID]; - entry.GID = [OFNumber numberWithUnsignedLong: - attributes.fileGroupOwnerAccountID]; - entry.owner = attributes.fileOwnerAccountName; - entry.group = attributes.fileGroupOwnerAccountName; + entry.ownerAccountID = + [attributes objectForKey: OFFileOwnerAccountID]; + entry.groupOwnerAccountID = + [attributes objectForKey: OFFileGroupOwnerAccountID]; + entry.ownerAccountName = + [attributes objectForKey: OFFileOwnerAccountName]; + entry.groupOwnerAccountName = + [attributes objectForKey: OFFileGroupOwnerAccountName]; #endif if ([type isEqual: OFFileTypeDirectory]) { entry.compressionMethod = @"-lhd-"; Index: utils/ofarc/TarArchive.m ================================================================== --- utils/ofarc/TarArchive.m +++ utils/ofarc/TarArchive.m @@ -31,14 +31,14 @@ static void setPermissions(OFString *path, OFTarArchiveEntry *entry) { #ifdef OF_FILE_MANAGER_SUPPORTS_PERMISSIONS - OFNumber *mode = [OFNumber numberWithUnsignedLongLong: - entry.mode.longLongValue & 0777]; + OFNumber *POSIXPermissions = [OFNumber numberWithUnsignedLongLong: + entry.POSIXPermissions.longLongValue & 0777]; OFFileAttributes attributes = [OFDictionary - dictionaryWithObject: mode + dictionaryWithObject: POSIXPermissions forKey: OFFilePOSIXPermissions]; [[OFFileManager defaultManager] setAttributes: attributes ofItemAtPath: path]; #endif @@ -115,14 +115,14 @@ if (app->_outputLevel >= 1) { OFString *date = [entry.modificationDate localDateStringWithFormat: @"%Y-%m-%d %H:%M:%S"]; OFString *size = [OFString stringWithFormat: @"%llu", entry.uncompressedSize]; - OFString *mode = [OFString stringWithFormat: - @"%06llo", entry.mode.unsignedLongLongValue]; - OFString *UID = entry.UID.description; - OFString *GID = entry.GID.description; + OFString *permissionsString = [OFString + stringWithFormat: + @"%llo", entry.POSIXPermissions + .unsignedLongLongValue]; [OFStdOut writeString: @"\t"]; [OFStdOut writeLine: OF_LOCALIZED(@"list_size", @"[" @" 'Size: '," @@ -131,35 +131,38 @@ @" {'': '%[size] bytes'}" @" ]" @"]".objectByParsingJSON, @"size", size)]; [OFStdOut writeString: @"\t"]; - [OFStdOut writeLine: OF_LOCALIZED(@"list_mode", - @"Mode: %[mode]", - @"mode", mode)]; - [OFStdOut writeString: @"\t"]; - [OFStdOut writeLine: OF_LOCALIZED(@"list_uid", - @"UID: %[uid]", - @"uid", UID)]; - [OFStdOut writeString: @"\t"]; - [OFStdOut writeLine: OF_LOCALIZED(@"list_gid", - @"GID: %[gid]", - @"gid", GID)]; - - if (entry.owner != nil) { - [OFStdOut writeString: @"\t"]; - [OFStdOut writeLine: OF_LOCALIZED( - @"list_owner", - @"Owner: %[owner]", - @"owner", entry.owner)]; - } - if (entry.group != nil) { - [OFStdOut writeString: @"\t"]; - [OFStdOut writeLine: OF_LOCALIZED( - @"list_group", - @"Group: %[group]", - @"group", entry.group)]; + [OFStdOut writeLine: + OF_LOCALIZED(@"list_posix_permissions", + @"POSIX permissions: %[perm]", + @"perm", permissionsString)]; + [OFStdOut writeString: @"\t"]; + [OFStdOut writeLine: OF_LOCALIZED( + @"list_owner_account_id", + @"Owner account ID: %[id]", + @"id", entry.ownerAccountID)]; + [OFStdOut writeString: @"\t"]; + [OFStdOut writeLine: OF_LOCALIZED( + @"list_group_owner_account_id", + @"Group owner account ID: %[id]", + @"id", entry.groupOwnerAccountID)]; + + if (entry.ownerAccountName != nil) { + [OFStdOut writeString: @"\t"]; + [OFStdOut writeLine: OF_LOCALIZED( + @"list_owner_account_name", + @"Owner account name: %[name]", + @"name", entry.ownerAccountName)]; + } + if (entry.groupOwnerAccountName != nil) { + [OFStdOut writeString: @"\t"]; + [OFStdOut writeLine: OF_LOCALIZED( + @"list_group_owner_account_name", + @"Group owner account name: %[name]", + @"name", entry.groupOwnerAccountName)]; } [OFStdOut writeString: @"\t"]; [OFStdOut writeLine: OF_LOCALIZED( @"list_modification_date", @@ -476,21 +479,24 @@ attributes = [fileManager attributesOfItemAtPath: fileName]; type = attributes.fileType; entry = [OFMutableTarArchiveEntry entryWithFileName: fileName]; #ifdef OF_FILE_MANAGER_SUPPORTS_PERMISSIONS - entry.mode = [attributes objectForKey: OFFilePOSIXPermissions]; + entry.POSIXPermissions = + [attributes objectForKey: OFFilePOSIXPermissions]; #endif entry.uncompressedSize = attributes.fileSize; entry.modificationDate = attributes.fileModificationDate; #ifdef OF_FILE_MANAGER_SUPPORTS_OWNER - entry.UID = [attributes objectForKey: OFFileOwnerAccountID]; - entry.GID = + entry.ownerAccountID = + [attributes objectForKey: OFFileOwnerAccountID]; + entry.groupOwnerAccountID = [attributes objectForKey: OFFileGroupOwnerAccountID]; - entry.owner = attributes.fileOwnerAccountName; - entry.group = attributes.fileGroupOwnerAccountName; + entry.ownerAccountName = attributes.fileOwnerAccountName; + entry.groupOwnerAccountName = + attributes.fileGroupOwnerAccountName; #endif if ([type isEqual: OFFileTypeRegular]) entry.type = OFTarArchiveEntryTypeFile; else if ([type isEqual: OFFileTypeDirectory]) { Index: utils/ofarc/lang/de.json ================================================================== --- utils/ofarc/lang/de.json +++ utils/ofarc/lang/de.json @@ -73,13 +73,15 @@ [ {"size == 1": "1 Byte"}, {"": "%[size] Bytes"} ] ], - "list_mode": "Modus: %[mode]", - "list_owner": "Besitzer: %[owner]", - "list_group": "Gruppe: %[group]", + "list_posix_permissions": "POSIX-Berechtigungen: %[perm]", + "list_owner_account_id": "Besitzerkontennummer: %[id]", + "list_group_owner_account_id": "Gruppenbesitzerkontennummer: %[id]", + "list_owner_account_name": "Besitzerkontenname: %[name]", + "list_group_owner_account_name": "Gruppebesitzerkontenname: %[name]", "list_header_level": "Header-Level: %[level]", "list_modification_date": "Änderungsdatum: %[date]", "list_type_normal": "Typ: Normale Datei", "list_type_hardlink": "Typ: Harter Link", "list_type_symlink": "Typ: Symbolischer Link",