Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vgqaK-005GbG-1Q for pgsql-hackers@arkaria.postgresql.org; Fri, 16 Jan 2026 20:38:21 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1vgqaJ-004zUL-1p for pgsql-hackers@arkaria.postgresql.org; Fri, 16 Jan 2026 20:38:19 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vgqaJ-004zUB-0d for pgsql-hackers@lists.postgresql.org; Fri, 16 Jan 2026 20:38:19 +0000 Received: from mail-ej1-x636.google.com ([2a00:1450:4864:20::636]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.96) (envelope-from ) id 1vgqaH-000sck-0Z for pgsql-hackers@lists.postgresql.org; Fri, 16 Jan 2026 20:38:19 +0000 Received: by mail-ej1-x636.google.com with SMTP id a640c23a62f3a-b876798b97eso409161866b.1 for ; Fri, 16 Jan 2026 12:38:16 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1768595896; cv=none; d=google.com; s=arc-20240605; b=dggOXk+YGHVWRUrM/PHeSxQCjl1PQfXSr+PQPLUX1nSIh7ZN/9LcDgM0xQ0044l79M NixldZkxAudyPrKCU3Tp6AIUGO7ByVOMp0BaYGTSV/4uc8xc8ICyKpkxTLDMZEyUkWLL ei022lfEjhEhkN0S3EyhBSOXWw7P3mk4jA9UiTeEoyar5ln2Ey5CG90m6C2C0jBeuu1S ouH2YT25wAEyFFvxC+QLCF9NLRppVG8LjlUeLSB5gaY9smqaVo0ilWFHP8ROAAS1Mf/K ATDHPEhgpIYOrSXLYcDfJQOAVRMnXeB1xvzGMsQQRZfdXKMVEM2NCBINJYN/giXJJT4o nZDg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:dkim-signature; bh=H9t8VaMWg7ukLzDITOnEkmO2AkGJBDmJXnZjYfVQGi0=; fh=aPVMrk07tKI8J9MCJvrVduXJIXB+3nNSKzEpAjvZq0s=; b=jQ7JuutVz/yVyNoCDsKDS6yZVzP82K2iJyDXJSTO99Y+edC7UPDxSBqsy5YH9lAhMo 3le/cEbNyNVkeG/yKgAt12wDKVob5k6nfkIRfsu3gCKik2T3iEbJPMcmckCqiuaMA8yy FHyuuAlL2G51jkAg442kiL1Jc7Fpv6t4CQ/zFs0zSSWJLAxC9VxiqQ2QbS64pC5r5O0/ 1+uKR2/buOUMSiRcg1S4XJgE4uMMrShrqAzB6ZZMVuWTTgwO186b5/5npyfuK6o5LiUo EXWgaQ39/Xi6AMkO4HGaiL4bpj9YtFt7C5L5bf8ihxssjjq1ES1zM49taLK9NAiVgUYX z+vQ==; darn=lists.postgresql.org ARC-Authentication-Results: i=1; mx.google.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1768595896; x=1769200696; darn=lists.postgresql.org; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:from:to:cc:subject:date:message-id:reply-to; bh=H9t8VaMWg7ukLzDITOnEkmO2AkGJBDmJXnZjYfVQGi0=; b=Srytg20twxDoGpQRQL2gL1qhguxpINaYO2FPfNPJ+OxbJif+dfpGvVQLvtdrudNEyt XyBRAuq/otJEGI1D3wG+LlNMVYSIpLnqfvFLfOv/zUiliugc9dOebMJo0eoy+Hi6KusU MwcpnWFuGRqOYS3zgah2D7RDWf4yikkoVhnGdnXz447A73LthNU4SMq3GGFpLiWUxWMc rBXO/pKUa5XIg6tsZmB4els017W/WyBdEVsQc0H+KrPZxztTucQpUXbMTo1Q8yvxXIBV YAekurv1oCpbBd9IcQDYfiAFt6r86V/I2D8vRo3QABdrUgxu6DWW6AYyPGJLssxkkLxq XcSg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1768595896; x=1769200696; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=H9t8VaMWg7ukLzDITOnEkmO2AkGJBDmJXnZjYfVQGi0=; b=VSqFDsfEkI/oXLxMQwMv7EV5n7Rl5y33V4TuC3ufN/B8PMxpCf1EJIQ6atmV6kCESs DcfPv7e3MevbZyKEAJDgZ5JPpjxYOjT37UDJDwCl7WaCkmn8A5r3PCoQlY+FFJ2+9sTb DpGUG6tGDPq1uWXiSB3T0vV1sOF7fgn6Sn+/Vkp8Uauw3xXuZOmJAEP2Z0b3fnRbz30t ozRRD731qKXb7AfceW/fIyha4T9qVdDBvQXTzvXN8K1qPyVh9PBqMZq7yKs8PczNWY9e y28N57QOFRdDZQcdmDYzGf072WCRwVo+mCa7IbHEqIexAukDCnFynDNZYTvvq9fz57zU yRXA== X-Forwarded-Encrypted: i=1; AJvYcCX04jm7CA9RQ50UR2ZJYwoaaFbCKHCPpoechofQgmjEnksaSQVonsEXO4Qel6BrpWwI+riRiQPRAiOnmqmk@lists.postgresql.org X-Gm-Message-State: AOJu0YwtN2dHda/TZq/KAN98MAWDHaBwJGyXg/LBMwAI2ByGqNo/4tuW AndS9Uitxx3Fc2Iv7Qv3Bccm9qcE9sw3v3Jahm9574GuygmNZAVXTKoXPEq6W3SxUHcLO8WhdPM cmluS7n+bTZXcyG7AdZl5c5f4+obJ2+8= X-Gm-Gg: AY/fxX4SO1kdjPmRS8G5eJCkWCNF0ZA2sTrYZH2E5pkJG5mZJCV3FCRm61ZJnBQNGNv i2wvmxbyZD5TNhw6eV6kOM8/fRUePYlegMw8QhshKeGenza9WN0JfgVIlc6dY4PD2N+doBI6oEA Edw9rjxN2e5JuEJdlDmb/oHrG7gGXgC7gwN025ACS+RV9EETJZuwnIdbN17vGk+1d8C24FVkEn6 YjO11JORg3CyUhE7xB0YYMoe7CxJaw6Iqn8p6IbQDN1eWtcrWEUby/E8BWT5SGo2pKaxBWw8u+V rUVtP/2edHn3rFDOTlZZ3Yv7y976o6/RNOJ1UA== X-Received: by 2002:a17:907:3e0b:b0:b87:6e21:824 with SMTP id a640c23a62f3a-b8792e14f18mr340994466b.23.1768595895195; Fri, 16 Jan 2026 12:38:15 -0800 (PST) MIME-Version: 1.0 References: <731ADE6F-01C5-4996-BAEE-5851DFC3F502@gmail.com> In-Reply-To: From: Robert Haas Date: Fri, 16 Jan 2026 15:38:03 -0500 X-Gm-Features: AZwV_QixZHFqKdRGWx7U_D1HfvdyiAU3DPp91YEFVxugFs0YfZ-fz5N4_fsSZeM Message-ID: Subject: Re: pg_waldump: support decoding of WAL inside tarfile To: Amul Sul Cc: Chao Li , Jakub Wartak , PostgreSQL Hackers Content-Type: multipart/mixed; boundary="00000000000015e56606488752c1" List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --00000000000015e56606488752c1 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable On Fri, Jan 2, 2026 at 7:30=E2=80=AFAM Amul Sul wrote: > Attached is the rebased version, includes some code comment improvements. Regarding 0001, I don't think that passing the WAL segment size around in a global variable is a good practice. It makes it hard to tell whether the variable is guaranteed to have been set properly at all the places where it is used. Of course, this patch set does not introduce that problem, but I think it could avoid making it worse by adding WalSegSz to XLogDumpPrivate instead of exporting the global variable everywhere. That struct seems to be available everyplace where we need the value. Actually, though, I'm inclined to remove the file-level global as well. Patch for that attached. I'm not against global variables in general, but I'm against global variables that are just there to avoid passing the right stuff around via function argument lists. 0002 claims to be just a refactoring but if (unlikely(private->endptr_reached)) return -1 is net new code, so I object. I realize this contradicts the review comment from Chao Li, but the principal that refactoring shouldn't change the logic is more important than whatever value we might get out of adding this sanity check here -- and I bet if we look into it we'll find that there are lots of other places in PostgreSQL that would also need to be changed if we wanted such a sanity check everywhere that we have code like this. I'd also like to point out that the commit message isn't really adequate to understand why this helps achieve the overall goal of the patch set. 0003 looks functionally correct but notice that you've stolen some but not all of the tests from the "# various ways of specifying WAL range" section without copying the comment or explaining in the commit message why you've moved some tests but not others. Regarding 0004: Instead of making ArchivedWAL_HTAB a global variable, can we just store a pointer to it in XLogDumpPrivate? (I would change the name to something else, something all lower case.) Or maybe the pointer should go someplace else, but I'm skeptical of a global variable here for the same reasons as 0001. I think ArchivedWALFile would be a better name than ArchivedWALEntry, and cur_wal_file or cur_file would be a better name than cur_wal. I'm extremely happy with the way that the hash table looks and the new logic in init_archive_reader() to make sure that we don't need to reread the beginning of the WAL but can reuse the data already read. That seems like a huge improvement to me. + if (recptr >=3D endPtr) + { + /* Discard the buffered data */ + resetStringInfo(&entry->buf); + len =3D 0; + + /* + * Push back the partial page data for the current page to the + * buffer, ensuring it remains full page available for re-reading + * if requested. + */ + if (p > readBuff) + { + Assert((count - nbytes) > 0); + appendBinaryStringInfo(&entry->buf, readBuff, count - nbytes); + } + } It feels pretty inelegant to me to pull data back into &entry->buf from readBuff here. I think what you should do is just do this test once, before entering the while (nbytes > 0) loop. Then you'll always have p =3D=3D readBuff, so the nested if statement is no longer required. Also, the way you have it, if this triggers for the first loop iteration, it will trigger for every subsquent loop iteration, which seems wasteful. + if (len > 0 && recptr > startPtr) + { + int skipBytes =3D 0; + + /* + * The required offset is not at the start of the buffer, so skip + * bytes until reaching the desired offset of the target page. + */ + skipBytes =3D recptr - startPtr; + + buf +=3D skipBytes; + len -=3D skipBytes; + } This logic seems pretty confusing. It looks as though len can go negative, because what if skipBytes > len? I'm not sure that's really possible here, but there's no comments explaining why it can't and no assertion verifying that it doesn't. I think you should probably try to unify this with the following if statement that is gated by (len > 0). In other places where we have code like this, what I've usually found useful is to compute the number of bytes to copy as Min(bytes available from source, bytes that will fit into the target), and I think that technique might be useful here. For example, in BlockRefTableRead, length is always the number of bytes that the caller wants which we haven't yet read, and we compute bytes_to_copy =3D Min(length, buffer->used - buffer->cursor). We then memcpy(data, &buffer->data[buffer->cursor], bytes_to_copy) and then adjust data and length. A similar bit of code not written by me can be found in WALReadFromBuffers, which maintains nbytes as the remaining number of bytes to be copied and then computes the size of the next copy as npagebytes =3D Min(nbytes, XLOG_BLCKSZ - offset). I think your if (len > 0 && recptr > startPtr) block is trying to do something similar to what the Min() is doing in those examples, but I find it hard to understand whether it is doing it correctly. I think you need some combination of clearer variable names, more comments, and/or rewriting this to be easier to read and understand without help. + entry =3D privateInfo->cur_wal; + + /* Fetch more data */ + if (read_archive_file(privateInfo, READ_CHUNK_SIZE) =3D=3D = 0) + break; /* archive file ended */ Why do we set entry to privateInfo->cur_wal and then call read_archive_file() afterwards? Doesn't read_archive_file() have the potential to change cur_wal? If so, don't we want to look at the entry that is current after we've called read_archive_file(), rather than before? Also, to harp on the naming a bit more, stuff like entry =3D privateInfo->cur_wal kind of shows that you haven't made the naming real consistent. This could be more clear if it said something like wal_file =3D privateInfo->cur_wal_file. + /* Found the required entry */ + if (entry->segno =3D=3D segno) + return entry; + + /* + * Ignore if the timeline is different or the current segment is not + * the desired one. + */ + if (privateInfo->timeline !=3D entry->timeline || + privateInfo->startSegNo > entry->segno || + privateInfo->endSegNo < entry->segno) + { + privateInfo->cur_wal =3D NULL; + continue; + } + I don't really understand what's happening here. One thing that's odd is that the first of these two if statements considers the timeline and the second does not. It seems unlikely that this is correct. I suspect that the hash table needs to be keyed by (TLI, segno) rather than just by TLI, and that get_archive_wal_entry needs to take both a TLI and a segment number as an argument. Otherwise, what could possibly prevent the first if statement from returning the correct segment from the wrong timeline? (Likewise, I think stuff in 0005 like prepare_tmp_write() should work on a TLI and a segno, not just a segno. There probably should be very few places in the patch where you pass only a segno and no TLI. get_tmp_walseg_path() is a pretty clear sign of the problem: If you were including the TLI in the file name, you would just use XLogFileName() here, but because you left out the TLI, you end up having to invent your own file naming convention. That seems pretty bad: wouldn't we like the temporary file names to have the same names as the files inside the archive? What happens if the same WAL file exists in the archive with two different TLIs?) Another thing that's odd is: why is this function resetting privateInfo->cur_wal to NULL? I feel like it should be the job of astreamer_waldump_content() to manage the value of privateInfo->cur_wal, and this function doesn't seem to have any business touching it. Even if it thinks that we want to ignore that WAL file for purposes of *this* call to get_archive_wal_entry(), surely it has no right to decide that the *next* call to this function should ignore that entry as well. Honestly, I don't really understand why we need to poke into privateInfo at all here. I feel like the shape of this loop should be: while (1) { if (read_archive_file(...) =3D=3D 0) break; if (we have the correct entry) return entry; } }. It seems to me that it ought to be the job of the archive streamer to handle everything else, including buffering more data and spilling to files. This should just iterate, repeatedly calling read_archive_file(), until we either get to the file we want or run out of archive. + /* + * XXX: If the segment being read not the requested one, the data must + * be buffered, as we currently lack the mechanism to write it to a + * temporary file. This is a known limitation that will be fixed in the + * next patch, as the buffer could grow up to the full WAL segment + * size. + */ + if (segno > entry->segno) + continue; I couldn't figure out what was going on here for a while. Then I realized that this makes some sense: if (segno > entry->segno), that means that the segment number that we've found in the archive is older than the requested segment number. Because we don't back up, that means we don't need the data. I think the idea is that we would fall through here and buffer the data if this if-test fails, but patch 0005 actually removes these two lines of code, so I think something here is kind of messed up. I think the result will be that with both patches applied, we'll buffer data we don't actually need for anything. Generally, I think that some details here should be revisited: +typedef struct ArchivedWALEntry +{ + uint32 status; /* hash status */ + XLogSegNo segno; /* hash key: WAL segment number */ + TimeLineID timeline; /* timeline of this wal fil= e */ + + StringInfoData buf; + bool tmpseg_exists; /* spill file exists? */ + + int total_read; /* total read of archived WAL segment */ +} ArchivedWALEntry; The first few members are great, except that timeline needs to be part of the hash key as well, so you probably need to make a two-element struct with a segno and a TLI and make that struct be the thing that comes right after status. After that, I'm not so sure. Essentially, I think what's happening here is that segno*file_size+total_read is the end LSN for buf, and the start LSN value is that value minus buf.len. And if tmpseg_exists is true, then the buffer might be empty, and you can read however much of the segment we found from the temp file. I find that confusing. If we're going to do something like this, I feel like it would make more sense to store XLogRecPtr starttli instead of int total_read, so that we explicitly mention the first LSN stored in the buffer, and you infer the ending LSN from the length of the buffer. But, stepping back a bit, why do we have a StringInfoData in every ArchivedWALEntry? It makes sense to do it that way if we're going to buffer all of the WAL data in memory. In that case, you need a separate buffer for every ArchivedWALEntry, and so this is logical. But if we're going to spill to disk, then there should only ever be one buffer in use at any given time, so why have a buffer in every ArchivedWALEntry instead of a single buffer inside of XLogDumpPrivate? We could choose to treat the hash table as the set of previous segments for which we have written data to disk, and the current segment and any associated buffer would be tracked inside the XLogDumpPrivate or astreamer_waldump, which would mean that only one copy of them would exist. I'm tempted to say that the direction I'm sketching here is the right way to go, but I'm not 100% certain that's true. It could be write to have a buffer per WAL file, as you have here, but if so, we should know why we're doing that and how it fits into the design, and I'm not currently seeing a real reason for it. + if (strstr(member->pathname, "PaxHeaders.")) + return false; There is no way that a filename containing the string "PaxHeaders." could ever pass the IsXLogFileName test just above. We shouldn't need this. --=20 Robert Haas EDB: http://www.enterprisedb.com --00000000000015e56606488752c1 Content-Type: application/octet-stream; name="0001-Remove-file-level-global-WalSegSz.patch.nocfbot" Content-Disposition: attachment; filename="0001-Remove-file-level-global-WalSegSz.patch.nocfbot" Content-Transfer-Encoding: base64 Content-ID: X-Attachment-Id: f_mkhcawlo0 RnJvbSA5YjZiYzRlMGZkYmIzZDZjN2U3ZjE5ZWJiMjY3YWUyODU0OWI1MDc2IE1vbiBTZXAgMTcg MDA6MDA6MDAgMjAwMQpGcm9tOiBSb2JlcnQgSGFhcyA8cmhhYXNAcG9zdGdyZXNxbC5vcmc+CkRh dGU6IEZyaSwgMTYgSmFuIDIwMjYgMDg6MzU6MTQgLTA1MDAKU3ViamVjdDogW1BBVENIIHYxXSBS ZW1vdmUgZmlsZS1sZXZlbCBnbG9iYWwgV2FsU2VnU3ouCgpJdCdzIGJldHRlciBzdHlsZSB0byBw YXNzIHRoZSB2YWx1ZSBhcm91bmQgdG8ganVzdCB0aGUgcGxhY2VzIHRoYXQKbmVlZCBpdC4gVGhp cyBtYWtlcyBpdCBlYXNpZXIgdG8gZGV0ZXJtaW5lIHdoZXRoZXIgdGhlIHZhbHVlIGlzCmFsd2F5 cyBwcm9wZXJseSBpbml0aWFsaXplZCBiZWZvcmUgdXNlLgotLS0KIHNyYy9iaW4vcGdfd2FsZHVt cC9wZ193YWxkdW1wLmMgfCAzNyArKysrKysrKysrKysrKysrKy0tLS0tLS0tLS0tLS0tLS0KIDEg ZmlsZSBjaGFuZ2VkLCAxOSBpbnNlcnRpb25zKCspLCAxOCBkZWxldGlvbnMoLSkKCmRpZmYgLS1n aXQgYS9zcmMvYmluL3BnX3dhbGR1bXAvcGdfd2FsZHVtcC5jIGIvc3JjL2Jpbi9wZ193YWxkdW1w L3BnX3dhbGR1bXAuYwppbmRleCBhYWU2NTU5NjZlZi4uZjM0NDYzODVkNmEgMTAwNjQ0Ci0tLSBh L3NyYy9iaW4vcGdfd2FsZHVtcC9wZ193YWxkdW1wLmMKKysrIGIvc3JjL2Jpbi9wZ193YWxkdW1w L3BnX3dhbGR1bXAuYwpAQCAtMzksNyArMzksNiBAQAogCiBzdGF0aWMgY29uc3QgY2hhciAqcHJv Z25hbWU7CiAKLXN0YXRpYyBpbnQJV2FsU2VnU3o7CiBzdGF0aWMgdm9sYXRpbGUgc2lnX2F0b21p Y190IHRpbWVfdG9fc3RvcCA9IGZhbHNlOwogCiBzdGF0aWMgY29uc3QgUmVsRmlsZUxvY2F0b3Ig ZW1wdHlSZWxGaWxlTG9jYXRvciA9IHswLCAwLCAwfTsKQEAgLTIwMywxMSArMjAyLDExIEBAIG9w ZW5fZmlsZV9pbl9kaXJlY3RvcnkoY29uc3QgY2hhciAqZGlyZWN0b3J5LCBjb25zdCBjaGFyICpm bmFtZSkKIC8qCiAgKiBUcnkgdG8gZmluZCBmbmFtZSBpbiB0aGUgZ2l2ZW4gZGlyZWN0b3J5LiBS ZXR1cm5zIHRydWUgaWYgaXQgaXMgZm91bmQsCiAgKiBmYWxzZSBvdGhlcndpc2UuIElmIGZuYW1l IGlzIE5VTEwsIHNlYXJjaCB0aGUgY29tcGxldGUgZGlyZWN0b3J5IGZvciBhbnkKLSAqIGZpbGUg d2l0aCBhIHZhbGlkIFdBTCBmaWxlIG5hbWUuIElmIGZpbGUgaXMgc3VjY2Vzc2Z1bGx5IG9wZW5l ZCwgc2V0IHRoZQotICogd2FsIHNlZ21lbnQgc2l6ZS4KKyAqIGZpbGUgd2l0aCBhIHZhbGlkIFdB TCBmaWxlIG5hbWUuIElmIGZpbGUgaXMgc3VjY2Vzc2Z1bGx5IG9wZW5lZCwgc2V0CisgKiAqV2FT ZWdTeiB0byB0aGUgV0FMIHNlZ21lbnQgc2l6ZS4KICAqLwogc3RhdGljIGJvb2wKLXNlYXJjaF9k aXJlY3RvcnkoY29uc3QgY2hhciAqZGlyZWN0b3J5LCBjb25zdCBjaGFyICpmbmFtZSkKK3NlYXJj aF9kaXJlY3RvcnkoY29uc3QgY2hhciAqZGlyZWN0b3J5LCBjb25zdCBjaGFyICpmbmFtZSwgaW50 ICpXYWxTZWdTeikKIHsKIAlpbnQJCQlmZCA9IC0xOwogCURJUgkJICAgKnhsZGlyOwpAQCAtMjQ5 LDE3ICsyNDgsMTcgQEAgc2VhcmNoX2RpcmVjdG9yeShjb25zdCBjaGFyICpkaXJlY3RvcnksIGNv bnN0IGNoYXIgKmZuYW1lKQogCQl7CiAJCQlYTG9nTG9uZ1BhZ2VIZWFkZXIgbG9uZ2hkciA9IChY TG9nTG9uZ1BhZ2VIZWFkZXIpIGJ1Zi5kYXRhOwogCi0JCQlXYWxTZWdTeiA9IGxvbmdoZHItPnhs cF9zZWdfc2l6ZTsKLQotCQkJaWYgKCFJc1ZhbGlkV2FsU2VnU2l6ZShXYWxTZWdTeikpCisJCQlp ZiAoIUlzVmFsaWRXYWxTZWdTaXplKGxvbmdoZHItPnhscF9zZWdfc2l6ZSkpCiAJCQl7CiAJCQkJ cGdfbG9nX2Vycm9yKG5nZXR0ZXh0KCJpbnZhbGlkIFdBTCBzZWdtZW50IHNpemUgaW4gV0FMIGZp bGUgXCIlc1wiICglZCBieXRlKSIsCiAJCQkJCQkJCQkgICJpbnZhbGlkIFdBTCBzZWdtZW50IHNp emUgaW4gV0FMIGZpbGUgXCIlc1wiICglZCBieXRlcykiLAotCQkJCQkJCQkJICBXYWxTZWdTeiks Ci0JCQkJCQkJIGZuYW1lLCBXYWxTZWdTeik7CisJCQkJCQkJCQkgIGxvbmdoZHItPnhscF9zZWdf c2l6ZSksCisJCQkJCQkJIGZuYW1lLCBsb25naGRyLT54bHBfc2VnX3NpemUpOwogCQkJCXBnX2xv Z19lcnJvcl9kZXRhaWwoIlRoZSBXQUwgc2VnbWVudCBzaXplIG11c3QgYmUgYSBwb3dlciBvZiB0 d28gYmV0d2VlbiAxIE1CIGFuZCAxIEdCLiIpOwogCQkJCWV4aXQoMSk7CiAJCQl9CisKKwkJCSpX YWxTZWdTeiA9IGxvbmdoZHItPnhscF9zZWdfc2l6ZTsKIAkJfQogCQllbHNlIGlmIChyIDwgMCkK IAkJCXBnX2ZhdGFsKCJjb3VsZCBub3QgcmVhZCBmaWxlIFwiJXNcIjogJW0iLApAQCAtMjg2LDIx ICsyODUsMjIgQEAgc2VhcmNoX2RpcmVjdG9yeShjb25zdCBjaGFyICpkaXJlY3RvcnksIGNvbnN0 IGNoYXIgKmZuYW1lKQogICoJIFhMT0dESVIgLwogICoJICRQR0RBVEEgLyBYTE9HRElSIC8KICAq Ci0gKiBUaGUgdmFsaWQgdGFyZ2V0IGRpcmVjdG9yeSBpcyByZXR1cm5lZC4KKyAqIFRoZSB2YWxp ZCB0YXJnZXQgZGlyZWN0b3J5IGlzIHJldHVybmVkLCBhbmQgKldhbFNlZ1N6IGlzIHNldCB0byB0 aGUKKyAqIHNpemUgb2YgdGhlIFdBTCBzZWdtZW50IGZvdW5kIGluIHRoYXQgZGlyZWN0b3J5Lgog ICovCiBzdGF0aWMgY2hhciAqCi1pZGVudGlmeV90YXJnZXRfZGlyZWN0b3J5KGNoYXIgKmRpcmVj dG9yeSwgY2hhciAqZm5hbWUpCitpZGVudGlmeV90YXJnZXRfZGlyZWN0b3J5KGNoYXIgKmRpcmVj dG9yeSwgY2hhciAqZm5hbWUsIGludCAqV2FsU2VnU3opCiB7CiAJY2hhcgkJZnBhdGhbTUFYUEdQ QVRIXTsKIAogCWlmIChkaXJlY3RvcnkgIT0gTlVMTCkKIAl7Ci0JCWlmIChzZWFyY2hfZGlyZWN0 b3J5KGRpcmVjdG9yeSwgZm5hbWUpKQorCQlpZiAoc2VhcmNoX2RpcmVjdG9yeShkaXJlY3Rvcnks IGZuYW1lLCBXYWxTZWdTeikpCiAJCQlyZXR1cm4gcGdfc3RyZHVwKGRpcmVjdG9yeSk7CiAKIAkJ LyogZGlyZWN0b3J5IC8gWExPR0RJUiAqLwogCQlzbnByaW50ZihmcGF0aCwgTUFYUEdQQVRILCAi JXMvJXMiLCBkaXJlY3RvcnksIFhMT0dESVIpOwotCQlpZiAoc2VhcmNoX2RpcmVjdG9yeShmcGF0 aCwgZm5hbWUpKQorCQlpZiAoc2VhcmNoX2RpcmVjdG9yeShmcGF0aCwgZm5hbWUsIFdhbFNlZ1N6 KSkKIAkJCXJldHVybiBwZ19zdHJkdXAoZnBhdGgpOwogCX0KIAllbHNlCkBAIC0zMDgsMTAgKzMw OCwxMCBAQCBpZGVudGlmeV90YXJnZXRfZGlyZWN0b3J5KGNoYXIgKmRpcmVjdG9yeSwgY2hhciAq Zm5hbWUpCiAJCWNvbnN0IGNoYXIgKmRhdGFkaXI7CiAKIAkJLyogY3VycmVudCBkaXJlY3Rvcnkg Ki8KLQkJaWYgKHNlYXJjaF9kaXJlY3RvcnkoIi4iLCBmbmFtZSkpCisJCWlmIChzZWFyY2hfZGly ZWN0b3J5KCIuIiwgZm5hbWUsIFdhbFNlZ1N6KSkKIAkJCXJldHVybiBwZ19zdHJkdXAoIi4iKTsK IAkJLyogWExPR0RJUiAqLwotCQlpZiAoc2VhcmNoX2RpcmVjdG9yeShYTE9HRElSLCBmbmFtZSkp CisJCWlmIChzZWFyY2hfZGlyZWN0b3J5KFhMT0dESVIsIGZuYW1lLCBXYWxTZWdTeikpCiAJCQly ZXR1cm4gcGdfc3RyZHVwKFhMT0dESVIpOwogCiAJCWRhdGFkaXIgPSBnZXRlbnYoIlBHREFUQSIp OwpAQCAtMzE5LDcgKzMxOSw3IEBAIGlkZW50aWZ5X3RhcmdldF9kaXJlY3RvcnkoY2hhciAqZGly ZWN0b3J5LCBjaGFyICpmbmFtZSkKIAkJaWYgKGRhdGFkaXIgIT0gTlVMTCkKIAkJewogCQkJc25w cmludGYoZnBhdGgsIE1BWFBHUEFUSCwgIiVzLyVzIiwgZGF0YWRpciwgWExPR0RJUik7Ci0JCQlp ZiAoc2VhcmNoX2RpcmVjdG9yeShmcGF0aCwgZm5hbWUpKQorCQkJaWYgKHNlYXJjaF9kaXJlY3Rv cnkoZnBhdGgsIGZuYW1lLCBXYWxTZWdTeikpCiAJCQkJcmV0dXJuIHBnX3N0cmR1cChmcGF0aCk7 CiAJCX0KIAl9CkBAIC04MDEsNiArODAxLDcgQEAgbWFpbihpbnQgYXJnYywgY2hhciAqKmFyZ3Yp CiAJWExvZ1JlY1B0cglmaXJzdF9yZWNvcmQ7CiAJY2hhcgkgICAqd2FsZGlyID0gTlVMTDsKIAlj aGFyCSAgICplcnJvcm1zZzsKKwlpbnQJCQlXYWxTZWdTejsKIAogCXN0YXRpYyBzdHJ1Y3Qgb3B0 aW9uIGxvbmdfb3B0aW9uc1tdID0gewogCQl7ImJrcC1kZXRhaWxzIiwgbm9fYXJndW1lbnQsIE5V TEwsICdiJ30sCkBAIC0xMTI3LDcgKzExMjgsNyBAQCBtYWluKGludCBhcmdjLCBjaGFyICoqYXJn dikKIAkJCQlwZ19mYXRhbCgiY291bGQgbm90IG9wZW4gZGlyZWN0b3J5IFwiJXNcIjogJW0iLCB3 YWxkaXIpOwogCQl9CiAKLQkJd2FsZGlyID0gaWRlbnRpZnlfdGFyZ2V0X2RpcmVjdG9yeSh3YWxk aXIsIGZuYW1lKTsKKwkJd2FsZGlyID0gaWRlbnRpZnlfdGFyZ2V0X2RpcmVjdG9yeSh3YWxkaXIs IGZuYW1lLCAmV2FsU2VnU3opOwogCQlmZCA9IG9wZW5fZmlsZV9pbl9kaXJlY3Rvcnkod2FsZGly LCBmbmFtZSk7CiAJCWlmIChmZCA8IDApCiAJCQlwZ19mYXRhbCgiY291bGQgbm90IG9wZW4gZmls ZSBcIiVzXCIiLCBmbmFtZSk7CkBAIC0xMTg5LDcgKzExOTAsNyBAQCBtYWluKGludCBhcmdjLCBj aGFyICoqYXJndikKIAkJfQogCX0KIAllbHNlCi0JCXdhbGRpciA9IGlkZW50aWZ5X3RhcmdldF9k aXJlY3Rvcnkod2FsZGlyLCBOVUxMKTsKKwkJd2FsZGlyID0gaWRlbnRpZnlfdGFyZ2V0X2RpcmVj dG9yeSh3YWxkaXIsIE5VTEwsICZXYWxTZWdTeik7CiAKIAkvKiB3ZSBkb24ndCBrbm93IHdoYXQg dG8gcHJpbnQgKi8KIAlpZiAoIVhMb2dSZWNQdHJJc1ZhbGlkKHByaXZhdGUuc3RhcnRwdHIpKQot LSAKMi41MS4wCgo= --00000000000015e56606488752c1--