4 * Copyright (C) 2006 Hans Leidekker
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "wine/port.h"
23 #include "wine/debug.h"
24 #include "wine/unicode.h"
29 #include <sys/types.h>
31 #ifdef HAVE_NETINET_IN_H
32 # include <netinet/in.h>
34 #ifdef HAVE_ARPA_NAMESER_H
35 # include <arpa/nameser.h>
48 WINE_DEFAULT_DEBUG_CHANNEL(dnsapi
);
50 const char *dns_type_to_str( unsigned short type
)
54 #define X(x) case (x): return #x;
112 default: { static char tmp
[7]; sprintf( tmp
, "0x%04x", type
); return tmp
; }
116 static int dns_strcmpX( LPCVOID str1
, LPCVOID str2
, BOOL wide
)
119 return lstrcmpiW( str1
, str2
);
121 return lstrcmpiA( str1
, str2
);
124 /******************************************************************************
125 * DnsRecordCompare [DNSAPI.@]
128 BOOL WINAPI
DnsRecordCompare( PDNS_RECORD r1
, PDNS_RECORD r2
)
133 TRACE( "(%p,%p)\n", r1
, r2
);
135 if (r1
->wType
!= r2
->wType
||
136 r1
->wDataLength
!= r2
->wDataLength
||
137 r1
->Flags
.S
.Section
!= r2
->Flags
.S
.Section
||
138 r1
->Flags
.S
.Delete
!= r2
->Flags
.S
.Delete
||
139 r1
->Flags
.S
.Unused
!= r2
->Flags
.S
.Unused
||
140 r1
->Flags
.S
.Reserved
!= r2
->Flags
.S
.Reserved
||
141 r1
->dwReserved
!= r2
->dwReserved
) return FALSE
;
143 wide
= (r1
->Flags
.S
.CharSet
== DnsCharSetUnicode
|| r1
->Flags
.S
.CharSet
== DnsCharSetUnknown
);
144 if (dns_strcmpX( r1
->pName
, r2
->pName
, wide
)) return FALSE
;
150 if (r1
->Data
.A
.IpAddress
!= r2
->Data
.A
.IpAddress
) return FALSE
;
155 if (r1
->Data
.SOA
.dwSerialNo
!= r2
->Data
.SOA
.dwSerialNo
||
156 r1
->Data
.SOA
.dwRefresh
!= r2
->Data
.SOA
.dwRefresh
||
157 r1
->Data
.SOA
.dwRetry
!= r2
->Data
.SOA
.dwRetry
||
158 r1
->Data
.SOA
.dwExpire
!= r2
->Data
.SOA
.dwExpire
||
159 r1
->Data
.SOA
.dwDefaultTtl
!= r2
->Data
.SOA
.dwDefaultTtl
)
161 if (dns_strcmpX( r1
->Data
.SOA
.pNamePrimaryServer
,
162 r2
->Data
.SOA
.pNamePrimaryServer
, wide
) ||
163 dns_strcmpX( r1
->Data
.SOA
.pNameAdministrator
,
164 r2
->Data
.SOA
.pNameAdministrator
, wide
))
177 if (dns_strcmpX( r1
->Data
.PTR
.pNameHost
,
178 r2
->Data
.PTR
.pNameHost
, wide
)) return FALSE
;
184 if (dns_strcmpX( r1
->Data
.MINFO
.pNameMailbox
,
185 r2
->Data
.MINFO
.pNameMailbox
, wide
) ||
186 dns_strcmpX( r1
->Data
.MINFO
.pNameErrorsMailbox
,
187 r2
->Data
.MINFO
.pNameErrorsMailbox
, wide
))
195 if (r1
->Data
.MX
.wPreference
!= r2
->Data
.MX
.wPreference
)
197 if (dns_strcmpX( r1
->Data
.MX
.pNameExchange
,
198 r2
->Data
.MX
.pNameExchange
, wide
))
207 if (r1
->Data
.TXT
.dwStringCount
!= r2
->Data
.TXT
.dwStringCount
)
209 for (i
= 0; i
< r1
->Data
.TXT
.dwStringCount
; i
++)
211 if (dns_strcmpX( r1
->Data
.TXT
.pStringArray
[i
],
212 r2
->Data
.TXT
.pStringArray
[i
], wide
))
219 if (r1
->Data
.Null
.dwByteCount
!= r2
->Data
.Null
.dwByteCount
)
221 if (memcmp( r1
->Data
.Null
.Data
,
222 r2
->Data
.Null
.Data
, r1
->Data
.Null
.dwByteCount
))
228 if (r1
->Data
.Opt
.wDataLength
!= r2
->Data
.Opt
.wDataLength
)
231 if (memcmp( r1
->Data
.Opt
.Data
,
232 r2
->Data
.Opt
.Data
, r1
->Data
.Opt
.wDataLength
))
238 for (i
= 0; i
< sizeof(IP6_ADDRESS
)/sizeof(DWORD
); i
++)
240 if (r1
->Data
.AAAA
.Ip6Address
.IP6Dword
[i
] !=
241 r2
->Data
.AAAA
.Ip6Address
.IP6Dword
[i
]) return FALSE
;
247 if (r1
->Data
.KEY
.wFlags
!= r2
->Data
.KEY
.wFlags
||
248 r1
->Data
.KEY
.chProtocol
!= r2
->Data
.KEY
.chProtocol
||
249 r1
->Data
.KEY
.chAlgorithm
!= r2
->Data
.KEY
.chAlgorithm
)
251 if (memcmp( r1
->Data
.KEY
.Key
, r2
->Data
.KEY
.Key
,
252 r1
->wDataLength
- sizeof(DNS_KEY_DATA
) + 1 ))
258 if (dns_strcmpX( r1
->Data
.SIG
.pNameSigner
,
259 r2
->Data
.SIG
.pNameSigner
, wide
))
261 if (r1
->Data
.SIG
.wTypeCovered
!= r2
->Data
.SIG
.wTypeCovered
||
262 r1
->Data
.SIG
.chAlgorithm
!= r2
->Data
.SIG
.chAlgorithm
||
263 r1
->Data
.SIG
.chLabelCount
!= r2
->Data
.SIG
.chLabelCount
||
264 r1
->Data
.SIG
.dwOriginalTtl
!= r2
->Data
.SIG
.dwOriginalTtl
||
265 r1
->Data
.SIG
.dwExpiration
!= r2
->Data
.SIG
.dwExpiration
||
266 r1
->Data
.SIG
.dwTimeSigned
!= r2
->Data
.SIG
.dwTimeSigned
||
267 r1
->Data
.SIG
.wKeyTag
!= r2
->Data
.SIG
.wKeyTag
)
269 if (memcmp( r1
->Data
.SIG
.Signature
, r2
->Data
.SIG
.Signature
,
270 r1
->wDataLength
- sizeof(DNS_SIG_DATAA
) + 1 ))
276 if (r1
->Data
.ATMA
.AddressType
!= r2
->Data
.ATMA
.AddressType
)
278 for (i
= 0; i
< DNS_ATMA_MAX_ADDR_LENGTH
; i
++)
280 if (r1
->Data
.ATMA
.Address
[i
] != r2
->Data
.ATMA
.Address
[i
])
287 if (dns_strcmpX( r1
->Data
.NXT
.pNameNext
,
288 r2
->Data
.NXT
.pNameNext
, wide
)) return FALSE
;
289 if (r1
->Data
.NXT
.wNumTypes
!= r2
->Data
.NXT
.wNumTypes
) return FALSE
;
290 if (memcmp( r1
->Data
.NXT
.wTypes
, r2
->Data
.NXT
.wTypes
,
291 r1
->wDataLength
- sizeof(DNS_NXT_DATAA
) + sizeof(WORD
) ))
297 if (dns_strcmpX( r1
->Data
.SRV
.pNameTarget
,
298 r2
->Data
.SRV
.pNameTarget
, wide
)) return FALSE
;
299 if (r1
->Data
.SRV
.wPriority
!= r2
->Data
.SRV
.wPriority
||
300 r1
->Data
.SRV
.wWeight
!= r2
->Data
.SRV
.wWeight
||
301 r1
->Data
.SRV
.wPort
!= r2
->Data
.SRV
.wPort
)
307 if (dns_strcmpX( r1
->Data
.TKEY
.pNameAlgorithm
,
308 r2
->Data
.TKEY
.pNameAlgorithm
, wide
))
310 if (r1
->Data
.TKEY
.dwCreateTime
!= r2
->Data
.TKEY
.dwCreateTime
||
311 r1
->Data
.TKEY
.dwExpireTime
!= r2
->Data
.TKEY
.dwExpireTime
||
312 r1
->Data
.TKEY
.wMode
!= r2
->Data
.TKEY
.wMode
||
313 r1
->Data
.TKEY
.wError
!= r2
->Data
.TKEY
.wError
||
314 r1
->Data
.TKEY
.wKeyLength
!= r2
->Data
.TKEY
.wKeyLength
||
315 r1
->Data
.TKEY
.wOtherLength
!= r2
->Data
.TKEY
.wOtherLength
||
316 r1
->Data
.TKEY
.cAlgNameLength
!= r2
->Data
.TKEY
.cAlgNameLength
||
317 r1
->Data
.TKEY
.bPacketPointers
!= r2
->Data
.TKEY
.bPacketPointers
)
320 /* FIXME: ignoring pAlgorithmPacket field */
321 if (memcmp( r1
->Data
.TKEY
.pKey
, r2
->Data
.TKEY
.pKey
,
322 r1
->Data
.TKEY
.wKeyLength
) ||
323 memcmp( r1
->Data
.TKEY
.pOtherData
, r2
->Data
.TKEY
.pOtherData
,
324 r1
->Data
.TKEY
.wOtherLength
)) return FALSE
;
329 if (dns_strcmpX( r1
->Data
.TSIG
.pNameAlgorithm
,
330 r2
->Data
.TSIG
.pNameAlgorithm
, wide
))
332 if (r1
->Data
.TSIG
.i64CreateTime
!= r2
->Data
.TSIG
.i64CreateTime
||
333 r1
->Data
.TSIG
.wFudgeTime
!= r2
->Data
.TSIG
.wFudgeTime
||
334 r1
->Data
.TSIG
.wOriginalXid
!= r2
->Data
.TSIG
.wOriginalXid
||
335 r1
->Data
.TSIG
.wError
!= r2
->Data
.TSIG
.wError
||
336 r1
->Data
.TSIG
.wSigLength
!= r2
->Data
.TSIG
.wSigLength
||
337 r1
->Data
.TSIG
.wOtherLength
!= r2
->Data
.TSIG
.wOtherLength
||
338 r1
->Data
.TSIG
.cAlgNameLength
!= r2
->Data
.TSIG
.cAlgNameLength
||
339 r1
->Data
.TSIG
.bPacketPointers
!= r2
->Data
.TSIG
.bPacketPointers
)
342 /* FIXME: ignoring pAlgorithmPacket field */
343 if (memcmp( r1
->Data
.TSIG
.pSignature
, r2
->Data
.TSIG
.pSignature
,
344 r1
->Data
.TSIG
.wSigLength
) ||
345 memcmp( r1
->Data
.TSIG
.pOtherData
, r2
->Data
.TSIG
.pOtherData
,
346 r1
->Data
.TSIG
.wOtherLength
)) return FALSE
;
351 if (r1
->Data
.WINS
.dwMappingFlag
!= r2
->Data
.WINS
.dwMappingFlag
||
352 r1
->Data
.WINS
.dwLookupTimeout
!= r2
->Data
.WINS
.dwLookupTimeout
||
353 r1
->Data
.WINS
.dwCacheTimeout
!= r2
->Data
.WINS
.dwCacheTimeout
||
354 r1
->Data
.WINS
.cWinsServerCount
!= r2
->Data
.WINS
.cWinsServerCount
)
356 if (memcmp( r1
->Data
.WINS
.WinsServers
, r2
->Data
.WINS
.WinsServers
,
357 r1
->wDataLength
- sizeof(DNS_WINS_DATA
) + sizeof(IP4_ADDRESS
) ))
363 if (r1
->Data
.WINSR
.dwMappingFlag
!= r2
->Data
.WINSR
.dwMappingFlag
||
364 r1
->Data
.WINSR
.dwLookupTimeout
!= r2
->Data
.WINSR
.dwLookupTimeout
||
365 r1
->Data
.WINSR
.dwCacheTimeout
!= r2
->Data
.WINSR
.dwCacheTimeout
)
367 if (dns_strcmpX( r1
->Data
.WINSR
.pNameResultDomain
,
368 r2
->Data
.WINSR
.pNameResultDomain
, wide
))
373 FIXME( "unknown type: %s\n", dns_type_to_str( r1
->wType
) );
379 static LPVOID
dns_strcpyX( LPCVOID src
, DNS_CHARSET in
, DNS_CHARSET out
)
383 case DnsCharSetUnicode
:
387 case DnsCharSetUnicode
: return dns_strdup_w( src
);
388 case DnsCharSetUtf8
: return dns_strdup_wu( src
);
389 case DnsCharSetAnsi
: return dns_strdup_wa( src
);
391 WARN( "unhandled target charset: %d\n", out
);
399 case DnsCharSetUnicode
: return dns_strdup_uw( src
);
400 case DnsCharSetUtf8
: return dns_strdup_u( src
);
401 case DnsCharSetAnsi
: return dns_strdup_ua( src
);
403 WARN( "unhandled target charset: %d\n", out
);
410 case DnsCharSetUnicode
: return dns_strdup_aw( src
);
411 case DnsCharSetUtf8
: return dns_strdup_au( src
);
412 case DnsCharSetAnsi
: return dns_strdup_a( src
);
414 WARN( "unhandled target charset: %d\n", out
);
419 WARN( "unhandled source charset: %d\n", in
);
425 /******************************************************************************
426 * DnsRecordCopyEx [DNSAPI.@]
429 PDNS_RECORD WINAPI
DnsRecordCopyEx( PDNS_RECORD src
, DNS_CHARSET in
, DNS_CHARSET out
)
432 unsigned int i
, size
;
434 TRACE( "(%p,%d,%d)\n", src
, in
, out
);
436 size
= FIELD_OFFSET(DNS_RECORD
, Data
) + src
->wDataLength
;
437 dst
= heap_alloc_zero( size
);
438 if (!dst
) return NULL
;
440 memcpy( dst
, src
, size
);
442 if (src
->Flags
.S
.CharSet
== DnsCharSetUtf8
||
443 src
->Flags
.S
.CharSet
== DnsCharSetAnsi
||
444 src
->Flags
.S
.CharSet
== DnsCharSetUnicode
) in
= src
->Flags
.S
.CharSet
;
446 dst
->Flags
.S
.CharSet
= out
;
447 dst
->pName
= dns_strcpyX( src
->pName
, in
, out
);
448 if (!dst
->pName
) goto error
;
457 for (i
= 0; i
< src
->Data
.TXT
.dwStringCount
; i
++)
459 dst
->Data
.TXT
.pStringArray
[i
] =
460 dns_strcpyX( src
->Data
.TXT
.pStringArray
[i
], in
, out
);
462 if (!dst
->Data
.TXT
.pStringArray
[i
])
464 while (i
> 0) heap_free( dst
->Data
.TXT
.pStringArray
[--i
] );
473 dst
->Data
.MINFO
.pNameMailbox
=
474 dns_strcpyX( src
->Data
.MINFO
.pNameMailbox
, in
, out
);
475 if (!dst
->Data
.MINFO
.pNameMailbox
) goto error
;
477 dst
->Data
.MINFO
.pNameErrorsMailbox
=
478 dns_strcpyX( src
->Data
.MINFO
.pNameErrorsMailbox
, in
, out
);
479 if (!dst
->Data
.MINFO
.pNameErrorsMailbox
)
481 heap_free( dst
->Data
.MINFO
.pNameMailbox
);
485 dst
->wDataLength
= sizeof(dst
->Data
.MINFO
);
486 if (out
== DnsCharSetUnicode
) dst
->wDataLength
+=
487 (strlenW( dst
->Data
.MINFO
.pNameMailbox
) + 1) * sizeof(WCHAR
) +
488 (strlenW( dst
->Data
.MINFO
.pNameErrorsMailbox
) + 1) * sizeof(WCHAR
);
495 dst
->Data
.MX
.pNameExchange
=
496 dns_strcpyX( src
->Data
.MX
.pNameExchange
, in
, out
);
497 if (!dst
->Data
.MX
.pNameExchange
) goto error
;
499 dst
->wDataLength
= sizeof(dst
->Data
.MX
);
500 if (out
== DnsCharSetUnicode
) dst
->wDataLength
+=
501 (strlenW( dst
->Data
.MX
.pNameExchange
) + 1) * sizeof(WCHAR
);
506 dst
->Data
.NXT
.pNameNext
=
507 dns_strcpyX( src
->Data
.NXT
.pNameNext
, in
, out
);
508 if (!dst
->Data
.NXT
.pNameNext
) goto error
;
510 dst
->wDataLength
= sizeof(dst
->Data
.NXT
);
511 if (out
== DnsCharSetUnicode
) dst
->wDataLength
+=
512 (strlenW( dst
->Data
.NXT
.pNameNext
) + 1) * sizeof(WCHAR
);
524 dst
->Data
.PTR
.pNameHost
=
525 dns_strcpyX( src
->Data
.PTR
.pNameHost
, in
, out
);
526 if (!dst
->Data
.PTR
.pNameHost
) goto error
;
528 dst
->wDataLength
= sizeof(dst
->Data
.PTR
);
529 if (out
== DnsCharSetUnicode
) dst
->wDataLength
+=
530 (strlenW( dst
->Data
.PTR
.pNameHost
) + 1) * sizeof(WCHAR
);
535 dst
->Data
.SIG
.pNameSigner
=
536 dns_strcpyX( src
->Data
.SIG
.pNameSigner
, in
, out
);
537 if (!dst
->Data
.SIG
.pNameSigner
) goto error
;
539 dst
->wDataLength
= sizeof(dst
->Data
.SIG
);
540 if (out
== DnsCharSetUnicode
) dst
->wDataLength
+=
541 (strlenW( dst
->Data
.SIG
.pNameSigner
) + 1) * sizeof(WCHAR
);
546 dst
->Data
.SOA
.pNamePrimaryServer
=
547 dns_strcpyX( src
->Data
.SOA
.pNamePrimaryServer
, in
, out
);
548 if (!dst
->Data
.SOA
.pNamePrimaryServer
) goto error
;
550 dst
->Data
.SOA
.pNameAdministrator
=
551 dns_strcpyX( src
->Data
.SOA
.pNameAdministrator
, in
, out
);
552 if (!dst
->Data
.SOA
.pNameAdministrator
)
554 heap_free( dst
->Data
.SOA
.pNamePrimaryServer
);
558 dst
->wDataLength
= sizeof(dst
->Data
.SOA
);
559 if (out
== DnsCharSetUnicode
) dst
->wDataLength
+=
560 (strlenW( dst
->Data
.SOA
.pNamePrimaryServer
) + 1) * sizeof(WCHAR
) +
561 (strlenW( dst
->Data
.SOA
.pNameAdministrator
) + 1) * sizeof(WCHAR
);
566 dst
->Data
.SRV
.pNameTarget
=
567 dns_strcpyX( src
->Data
.SRV
.pNameTarget
, in
, out
);
568 if (!dst
->Data
.SRV
.pNameTarget
) goto error
;
570 dst
->wDataLength
= sizeof(dst
->Data
.SRV
);
571 if (out
== DnsCharSetUnicode
) dst
->wDataLength
+=
572 (strlenW( dst
->Data
.SRV
.pNameTarget
) + 1) * sizeof(WCHAR
);
581 heap_free( dst
->pName
);
586 /******************************************************************************
587 * DnsRecordListFree [DNSAPI.@]
590 VOID WINAPI
DnsRecordListFree( PDNS_RECORD list
, DNS_FREE_TYPE type
)
592 DNS_RECORD
*r
, *next
;
595 TRACE( "(%p,%d)\n", list
, type
);
601 case DnsFreeRecordList
:
603 for (r
= list
; (list
= r
); r
= next
)
605 heap_free( r
->pName
);
614 for (i
= 0; i
< r
->Data
.TXT
.dwStringCount
; i
++)
615 heap_free( r
->Data
.TXT
.pStringArray
[i
] );
622 heap_free( r
->Data
.MINFO
.pNameMailbox
);
623 heap_free( r
->Data
.MINFO
.pNameErrorsMailbox
);
630 heap_free( r
->Data
.MX
.pNameExchange
);
635 heap_free( r
->Data
.NXT
.pNameNext
);
647 heap_free( r
->Data
.PTR
.pNameHost
);
652 heap_free( r
->Data
.SIG
.pNameSigner
);
657 heap_free( r
->Data
.SOA
.pNamePrimaryServer
);
658 heap_free( r
->Data
.SOA
.pNameAdministrator
);
663 heap_free( r
->Data
.SRV
.pNameTarget
);
676 case DnsFreeParsedMessageFields
:
678 FIXME( "unhandled free type: %d\n", type
);
682 WARN( "unknown free type: %d\n", type
);
687 /******************************************************************************
691 void WINAPI
DnsFree( PVOID data
, DNS_FREE_TYPE type
)
693 DnsRecordListFree( data
, type
);
696 /******************************************************************************
697 * DnsRecordSetCompare [DNSAPI.@]
700 BOOL WINAPI
DnsRecordSetCompare( PDNS_RECORD set1
, PDNS_RECORD set2
,
701 PDNS_RECORD
*diff1
, PDNS_RECORD
*diff2
)
704 DNS_RECORD
*r
, *t
, *u
;
707 TRACE( "(%p,%p,%p,%p)\n", set1
, set2
, diff1
, diff2
);
709 if (!set1
&& !set2
) return FALSE
;
711 if (diff1
) *diff1
= NULL
;
712 if (diff2
) *diff2
= NULL
;
716 if (diff1
) *diff1
= DnsRecordSetCopyEx( set1
, 0, set1
->Flags
.S
.CharSet
);
721 if (diff2
) *diff2
= DnsRecordSetCopyEx( set2
, 0, set2
->Flags
.S
.CharSet
);
725 DNS_RRSET_INIT( rr1
);
726 DNS_RRSET_INIT( rr2
);
728 for (r
= set1
; r
; r
= r
->pNext
)
730 for (t
= set2
; t
; t
= t
->pNext
)
732 u
= DnsRecordCopyEx( r
, r
->Flags
.S
.CharSet
, t
->Flags
.S
.CharSet
);
735 if (!DnsRecordCompare( t
, u
))
737 DNS_RRSET_ADD( rr1
, u
);
740 else DnsRecordListFree( u
, DnsFreeRecordList
);
744 for (t
= set2
; t
; t
= t
->pNext
)
746 for (r
= set1
; r
; r
= r
->pNext
)
748 u
= DnsRecordCopyEx( t
, t
->Flags
.S
.CharSet
, r
->Flags
.S
.CharSet
);
751 if (!DnsRecordCompare( r
, u
))
753 DNS_RRSET_ADD( rr2
, u
);
756 else DnsRecordListFree( u
, DnsFreeRecordList
);
760 DNS_RRSET_TERMINATE( rr1
);
761 DNS_RRSET_TERMINATE( rr2
);
763 if (diff1
) *diff1
= rr1
.pFirstRR
;
764 else DnsRecordListFree( rr1
.pFirstRR
, DnsFreeRecordList
);
766 if (diff2
) *diff2
= rr2
.pFirstRR
;
767 else DnsRecordListFree( rr2
.pFirstRR
, DnsFreeRecordList
);
772 DNS_RRSET_TERMINATE( rr1
);
773 DNS_RRSET_TERMINATE( rr2
);
775 DnsRecordListFree( rr1
.pFirstRR
, DnsFreeRecordList
);
776 DnsRecordListFree( rr2
.pFirstRR
, DnsFreeRecordList
);
781 /******************************************************************************
782 * DnsRecordSetCopyEx [DNSAPI.@]
785 PDNS_RECORD WINAPI
DnsRecordSetCopyEx( PDNS_RECORD src_set
, DNS_CHARSET in
, DNS_CHARSET out
)
788 DNS_RECORD
*src
, *dst
;
790 TRACE( "(%p,%d,%d)\n", src_set
, in
, out
);
792 DNS_RRSET_INIT( dst_set
);
794 for (src
= src_set
; (src_set
= src
); src
= src_set
->pNext
)
796 dst
= DnsRecordCopyEx( src
, in
, out
);
799 DNS_RRSET_TERMINATE( dst_set
);
800 DnsRecordListFree( dst_set
.pFirstRR
, DnsFreeRecordList
);
803 DNS_RRSET_ADD( dst_set
, dst
);
806 DNS_RRSET_TERMINATE( dst_set
);
807 return dst_set
.pFirstRR
;
810 /******************************************************************************
811 * DnsRecordSetDetach [DNSAPI.@]
814 PDNS_RECORD WINAPI
DnsRecordSetDetach( PDNS_RECORD set
)
818 TRACE( "(%p)\n", set
);
820 for (r
= set
; (set
= r
); r
= set
->pNext
)
822 if (r
->pNext
&& !r
->pNext
->pNext
)