ObjFW  Check-in [153f39636e]

Overview
Comment:Add support for extended attributes on NetBSD
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 153f39636e4a5af9c18549914e09a771a8dbbf445fcbed21ea188f116ef1867e
User & Date: js on 2024-04-07 22:05:05
Other Links: manifest | tags
Context
2024-04-07
23:23
Add support for extended attributes on FreeBSD check-in: a19dde73d4 user: js tags: trunk
22:05
Add support for extended attributes on NetBSD check-in: 153f39636e user: js tags: trunk
2024-04-03
20:51
OFFileIRIHandler: Fix missing retain + autorelease check-in: 98e5c7dd28 user: js tags: trunk
Changes

Modified src/OFFileIRIHandler.m from [ac0201bdd3] to [fa2705caf0].

35
36
37
38
39
40
41



42
43
44
45
46
47
48
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
#include <sys/time.h>
#if defined(OF_LINUX) || defined(OF_MACOS)
# include <sys/xattr.h>
#endif



#ifdef OF_HAIKU
# include <ctype.h>
# include <kernel/fs_attr.h>
#endif
#ifdef OF_WINDOWS
# include <utime.h>
#endif







>
>
>







35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
#include <sys/time.h>
#if defined(OF_LINUX) || defined(OF_MACOS)
# include <sys/xattr.h>
#endif
#ifdef OF_NETBSD
# include <sys/extattr.h>
#endif
#ifdef OF_HAIKU
# include <ctype.h>
# include <kernel/fs_attr.h>
#endif
#ifdef OF_WINDOWS
# include <utime.h>
#endif
377
378
379
380
381
382
383





















384
385
386
387
388
389
390
# endif

	return 0;
#else
	return statWrapper(path, buffer);
#endif
}






















static void
setTypeAttribute(OFMutableFileAttributes attributes, Stat *s)
{
	if (S_ISREG(s->st_mode))
		[attributes setObject: OFFileTypeRegular forKey: OFFileType];
	else if (S_ISDIR(s->st_mode))







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
# endif

	return 0;
#else
	return statWrapper(path, buffer);
#endif
}

#ifdef OF_NETBSD
static void
parseAttributeName(OFString **name, int *namespace)
{
	size_t pos = [*name rangeOfString: @"."].location;
	OFString *namespaceName;

	if (pos == OFNotFound)
		@throw [OFInvalidArgumentException exception];

	namespaceName = [*name substringToIndex: pos];

	if (extattr_string_to_namespace(
	    [namespaceName cStringWithEncoding: [OFLocale encoding]],
	    namespace) == -1)
		@throw [OFInvalidArgumentException exception];

	*name = [*name substringFromIndex: pos + 1];
}
#endif

static void
setTypeAttribute(OFMutableFileAttributes attributes, Stat *s)
{
	if (S_ISREG(s->st_mode))
		[attributes setObject: OFFileTypeRegular forKey: OFFileType];
	else if (S_ISDIR(s->st_mode))
598
599
600
601
602
603
604
605
606




607
608
609
610
611
612
613
	OFMutableArray *names = nil;
# if defined(OF_LINUX) || defined(OF_MACOS)
#  if defined(OF_LINUX)
	ssize_t size = llistxattr(cPath, NULL, 0);
#  elif defined(OF_MACOS)
	ssize_t size = listxattr(cPath, NULL, 0, XATTR_NOFOLLOW);
#  endif
	char *list = OFAllocMemory(1, size);





	@try {
		char *name;

#  if defined(OF_LINUX)
		if ((size = llistxattr(cPath, list, size)) < 0)
#  elif defined(OF_MACOS)
		if ((size = listxattr(cPath, list, size, XATTR_NOFOLLOW)) < 0)







|

>
>
>
>







622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
	OFMutableArray *names = nil;
# if defined(OF_LINUX) || defined(OF_MACOS)
#  if defined(OF_LINUX)
	ssize_t size = llistxattr(cPath, NULL, 0);
#  elif defined(OF_MACOS)
	ssize_t size = listxattr(cPath, NULL, 0, XATTR_NOFOLLOW);
#  endif
	char *list;

	if (size < 0)
		return;

	list = OFAllocMemory(1, size);
	@try {
		char *name;

#  if defined(OF_LINUX)
		if ((size = llistxattr(cPath, list, size)) < 0)
#  elif defined(OF_MACOS)
		if ((size = listxattr(cPath, list, size, XATTR_NOFOLLOW)) < 0)
625
626
627
628
629
630
631























































632
633
634
635
636
637
638
							       length: length]];

			name += length + 1;
			size -= length + 1;
		}
	} @finally {
		OFFreeMemory(list);























































	}
# elif defined(OF_HAIKU)
	DIR *dir = fs_open_attr_dir(cPath);

	if (dir == NULL)
		return;








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
							       length: length]];

			name += length + 1;
			size -= length + 1;
		}
	} @finally {
		OFFreeMemory(list);
	}
# elif defined(OF_NETBSD)
	names = [OFMutableArray array];

	for (size_t i = 0; extattr_namespaces[i] != 0; i++) {
		ssize_t size;
		char *list;

		if ((size = extattr_list_link(cPath, extattr_namespaces[i],
		    NULL, 0)) < 0)
			continue;

		list = OFAllocMemory(1, size);
		@try {
			OFString *namespace;
			char *cNamespace, *iter;

			if (extattr_namespace_to_string(
			    extattr_namespaces[i], &cNamespace) == -1)
				continue;

			namespace = [OFString stringWithCString: cNamespace
						       encoding: encoding];

			if ((size = extattr_list_link(cPath,
			    extattr_namespaces[i], list, size)) < 0)
				continue;

			iter = list;

			while (size > 0) {
				ssize_t length = *(unsigned char *)iter;
				OFString *name;

				iter++;
				size--;

				if (length > size)
					@throw [OFOutOfRangeException
					    exception];

				name = [OFString stringWithCString: iter
							  encoding: encoding
							    length: length];
				name = [OFString stringWithFormat:
				    @"%@.%@",  namespace, name];

				[names addObject: name];

				iter += length;
				size -= length;
			}
		} @finally {
			OFFreeMemory(list);
		}
	}
# elif defined(OF_HAIKU)
	DIR *dir = fs_open_attr_dir(cPath);

	if (dir == NULL)
		return;

1621
1622
1623
1624
1625
1626
1627
1628
1629
1630

1631
1632
1633
1634
1635
1636
1637
			 forName: (OFString *)name
		     ofItemAtIRI: (OFIRI *)IRI
{
	void *pool = objc_autoreleasePoolPush();
	OFString *path = IRI.fileSystemRepresentation;
	OFStringEncoding encoding = [OFLocale encoding];
	const char *cPath = [path cStringWithEncoding: encoding];
	const char *cName = [name cStringWithEncoding: encoding];
	void *value = NULL;
# if defined(OF_LINUX) || defined(OF_MACOS)

#  if defined(OF_LINUX)
	ssize_t size = lgetxattr(cPath, cName, NULL, 0);
#  elif defined(OF_MACOS)
	ssize_t size = getxattr(cPath, cName, NULL, 0, 0, XATTR_NOFOLLOW);
#  endif

	if (size < 0)







<


>







1704
1705
1706
1707
1708
1709
1710

1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
			 forName: (OFString *)name
		     ofItemAtIRI: (OFIRI *)IRI
{
	void *pool = objc_autoreleasePoolPush();
	OFString *path = IRI.fileSystemRepresentation;
	OFStringEncoding encoding = [OFLocale encoding];
	const char *cPath = [path cStringWithEncoding: encoding];

	void *value = NULL;
# if defined(OF_LINUX) || defined(OF_MACOS)
	const char *cName = [name cStringWithEncoding: encoding];
#  if defined(OF_LINUX)
	ssize_t size = lgetxattr(cPath, cName, NULL, 0);
#  elif defined(OF_MACOS)
	ssize_t size = getxattr(cPath, cName, NULL, 0, 0, XATTR_NOFOLLOW);
#  endif

	if (size < 0)
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663































1664

1665
1666
1667
1668
1669
1670
1671
		*data = [OFData dataWithItemsNoCopy: value
					      count: size
				       freeWhenDone: true];
		value = NULL;
	} @finally {
		OFFreeMemory(value);
	}

	if (type != NULL)
		*type = nil;































# elif defined(OF_HAIKU)

	int fd = open(cPath, O_RDONLY);
	struct attr_info info;

	if (fd == -1)
		@throw [OFGetItemAttributesFailedException
		    exceptionWithIRI: IRI
			       errNo: errno];










>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

>







1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
		*data = [OFData dataWithItemsNoCopy: value
					      count: size
				       freeWhenDone: true];
		value = NULL;
	} @finally {
		OFFreeMemory(value);
	}

	if (type != NULL)
		*type = nil;
# elif defined(OF_NETBSD)
	int namespace;
	const char *cName;
	ssize_t size;

	parseAttributeName(&name, &namespace);
	cName = [name cStringWithEncoding: encoding];

	if ((size = extattr_get_link(cPath, namespace, cName, NULL, 0)) < 0)
		@throw [OFGetItemAttributesFailedException
		    exceptionWithIRI: IRI
			       errNo: errno];

	value = OFAllocMemory(1, size);
	@try {
		if ((size = extattr_get_link(cPath, namespace, cName,
		    value, size)) < 0)
			@throw [OFGetItemAttributesFailedException
			    exceptionWithIRI: IRI
				       errNo: errno];

		*data = [OFData dataWithItemsNoCopy: value
					      count: size
				       freeWhenDone: true];
		value = NULL;
	} @finally {
		OFFreeMemory(value);
	}

	if (type != NULL)
		*type = nil;
# elif defined(OF_HAIKU)
	const char *cName = [name cStringWithEncoding: encoding];
	int fd = open(cPath, O_RDONLY);
	struct attr_info info;

	if (fd == -1)
		@throw [OFGetItemAttributesFailedException
		    exceptionWithIRI: IRI
			       errNo: errno];
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727


1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745

























1746

1747
1748
1749
1750
1751
1752
1753
			 forName: (OFString *)name
		     ofItemAtIRI: (OFIRI *)IRI
{
	void *pool = objc_autoreleasePoolPush();
	OFString *path = IRI.fileSystemRepresentation;
	OFStringEncoding encoding = [OFLocale encoding];
	const char *cPath = [path cStringWithEncoding: encoding];
	const char *cName = [name cStringWithEncoding: encoding];
	size_t size = data.count * data.itemSize;

# if defined(OF_LINUX) || defined(OF_MACOS)


	if (type != nil)
		@throw [OFNotImplementedException exceptionWithSelector: _cmd
								 object: self];

#  if defined(OF_LINUX)
	if (lsetxattr(cPath, cName, data.items, size, 0) != 0) {
#  elif defined(OF_MACOS)
	if (setxattr(cPath, cName, data.items, size, 0, XATTR_NOFOLLOW) != 0) {
#  endif
		int errNo = errno;

		/* TODO: Add an attribute (prefix?) for extended attributes? */
		@throw [OFSetItemAttributesFailedException
		    exceptionWithIRI: IRI
			  attributes: [OFDictionary dictionary]
		     failedAttribute: @""
			       errNo: errNo];
	}

























# elif defined(OF_HAIKU)

	unsigned long long typeInt;
	int fd;

	if (type != nil && ![type isKindOfClass: [OFNumber class]])
		@throw [OFInvalidArgumentException exception];

	typeInt = (type != nil ? [type unsignedLongLongValue] : 0);







<



>
>


















>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

>







1832
1833
1834
1835
1836
1837
1838

1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
			 forName: (OFString *)name
		     ofItemAtIRI: (OFIRI *)IRI
{
	void *pool = objc_autoreleasePoolPush();
	OFString *path = IRI.fileSystemRepresentation;
	OFStringEncoding encoding = [OFLocale encoding];
	const char *cPath = [path cStringWithEncoding: encoding];

	size_t size = data.count * data.itemSize;

# if defined(OF_LINUX) || defined(OF_MACOS)
	const char *cName = [name cStringWithEncoding: encoding];

	if (type != nil)
		@throw [OFNotImplementedException exceptionWithSelector: _cmd
								 object: self];

#  if defined(OF_LINUX)
	if (lsetxattr(cPath, cName, data.items, size, 0) != 0) {
#  elif defined(OF_MACOS)
	if (setxattr(cPath, cName, data.items, size, 0, XATTR_NOFOLLOW) != 0) {
#  endif
		int errNo = errno;

		/* TODO: Add an attribute (prefix?) for extended attributes? */
		@throw [OFSetItemAttributesFailedException
		    exceptionWithIRI: IRI
			  attributes: [OFDictionary dictionary]
		     failedAttribute: @""
			       errNo: errNo];
	}
# elif defined(OF_NETBSD)
	int namespace;
	const char *cName;

	if (size > SSIZE_MAX)
		@throw [OFOutOfRangeException exception];

	if (type != nil)
		@throw [OFNotImplementedException exceptionWithSelector: _cmd
								 object: self];

	parseAttributeName(&name, &namespace);
	cName = [name cStringWithEncoding: encoding];

	if (extattr_set_link(cPath, namespace, cName, data.items, size) !=
	    (ssize_t)size) {
		int errNo = errno;

		/* TODO: Add an attribute (prefix?) for extended attributes? */
		@throw [OFSetItemAttributesFailedException
		    exceptionWithIRI: IRI
			  attributes: [OFDictionary dictionary]
		     failedAttribute: @""
			       errNo: errNo];
	}
# elif defined(OF_HAIKU)
	const char *cName = [name cStringWithEncoding: encoding];
	unsigned long long typeInt;
	int fd;

	if (type != nil && ![type isKindOfClass: [OFNumber class]])
		@throw [OFInvalidArgumentException exception];

	typeInt = (type != nil ? [type unsignedLongLongValue] : 0);
1794
1795
1796
1797
1798
1799
1800

1801
1802
1803
1804
1805
1806
1807
1808
1809

















1810
1811
1812
1813
1814
1815
1816
- (void)removeExtendedAttributeForName: (OFString *)name
			   ofItemAtIRI: (OFIRI *)IRI
{
	void *pool = objc_autoreleasePoolPush();
	OFString *path = IRI.fileSystemRepresentation;
	OFStringEncoding encoding = [OFLocale encoding];
	const char *cPath = [path cStringWithEncoding: encoding];

	const char *cName = [name cStringWithEncoding: encoding];

# if defined(OF_LINUX) || defined(OF_MACOS)
#  if defined(OF_LINUX)
	if (lremovexattr(cPath, cName) != 0) {
#  elif defined(OF_MACOS)
	if (removexattr(cPath, cName, XATTR_NOFOLLOW) != 0) {
#  endif
		int errNo = errno;


















		/* TODO: Add an attribute (prefix?) for extended attributes? */
		@throw [OFSetItemAttributesFailedException
		    exceptionWithIRI: IRI
			  attributes: [OFDictionary dictionary]
		     failedAttribute: @""
			       errNo: errNo];







>


<






>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







1936
1937
1938
1939
1940
1941
1942
1943
1944
1945

1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
- (void)removeExtendedAttributeForName: (OFString *)name
			   ofItemAtIRI: (OFIRI *)IRI
{
	void *pool = objc_autoreleasePoolPush();
	OFString *path = IRI.fileSystemRepresentation;
	OFStringEncoding encoding = [OFLocale encoding];
	const char *cPath = [path cStringWithEncoding: encoding];
# if defined(OF_LINUX) || defined(OF_MACOS)
	const char *cName = [name cStringWithEncoding: encoding];


#  if defined(OF_LINUX)
	if (lremovexattr(cPath, cName) != 0) {
#  elif defined(OF_MACOS)
	if (removexattr(cPath, cName, XATTR_NOFOLLOW) != 0) {
#  endif
		int errNo = errno;

		/* TODO: Add an attribute (prefix?) for extended attributes? */
		@throw [OFSetItemAttributesFailedException
		    exceptionWithIRI: IRI
			  attributes: [OFDictionary dictionary]
		     failedAttribute: @""
			       errNo: errNo];
	}
# elif defined(OF_NETBSD)
	int namespace;
	const char *cName;

	parseAttributeName(&name, &namespace);
	cName = [name cStringWithEncoding: encoding];

	if (extattr_delete_link(cPath, namespace, cName) != 0) {
		int errNo = errno;

		/* TODO: Add an attribute (prefix?) for extended attributes? */
		@throw [OFSetItemAttributesFailedException
		    exceptionWithIRI: IRI
			  attributes: [OFDictionary dictionary]
		     failedAttribute: @""
			       errNo: errNo];

Modified src/OFFileManager.h from [d46ba4ebbc] to [575b6eb634].

35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
    defined(OF_WINDOWS) || defined(DOXYGEN)
#  define OF_FILE_MANAGER_SUPPORTS_LINKS
# endif
# if (defined(OF_HAVE_SYMLINK) && !defined(OF_AMIGAOS)) || \
    defined(OF_WINDOWS) || defined(DOXYGEN)
#  define OF_FILE_MANAGER_SUPPORTS_SYMLINKS
# endif
# if defined(OF_LINUX) || defined(OF_MACOS) ||defined(OF_HAIKU) || \
    defined(DOXYGEN)
#  define OF_FILE_MANAGER_SUPPORTS_EXTENDED_ATTRIBUTES
# endif
#endif

@class OFArray OF_GENERIC(ObjectType);
@class OFConstantString;
@class OFDate;







|
|







35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
    defined(OF_WINDOWS) || defined(DOXYGEN)
#  define OF_FILE_MANAGER_SUPPORTS_LINKS
# endif
# if (defined(OF_HAVE_SYMLINK) && !defined(OF_AMIGAOS)) || \
    defined(OF_WINDOWS) || defined(DOXYGEN)
#  define OF_FILE_MANAGER_SUPPORTS_SYMLINKS
# endif
# if defined(OF_LINUX) || defined(OF_MACOS) || defined(OF_NETBSD) || \
    defined(OF_HAIKU) || defined(DOXYGEN)
#  define OF_FILE_MANAGER_SUPPORTS_EXTENDED_ATTRIBUTES
# endif
#endif

@class OFArray OF_GENERIC(ObjectType);
@class OFConstantString;
@class OFDate;

Modified tests/OFFileManagerTests.m from [b78b36e860] to [ff06e4c90e].

368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
	OFArray *extendedAttributeNames;

	@try {
		[_fileManager setExtendedAttributeData: data
					       forName: @"user.test"
					  ofItemAtPath: testFilePath];
	} @catch (OFSetItemAttributesFailedException *e) {
		if (e.errNo != ENOTSUP)
			@throw e;

		OTSkip(@"Extended attributes are not supported");
	}

	attributes = [_fileManager attributesOfItemAtIRI: _testFileIRI];
	extendedAttributeNames =







|







368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
	OFArray *extendedAttributeNames;

	@try {
		[_fileManager setExtendedAttributeData: data
					       forName: @"user.test"
					  ofItemAtPath: testFilePath];
	} @catch (OFSetItemAttributesFailedException *e) {
		if (e.errNo != ENOTSUP && e.errNo != EOPNOTSUPP)
			@throw e;

		OTSkip(@"Extended attributes are not supported");
	}

	attributes = [_fileManager attributesOfItemAtIRI: _testFileIRI];
	extendedAttributeNames =