public inbox for pve-devel@lists.proxmox.com
 help / color / mirror / Atom feed
* [pve-devel] [PATCH proxmox 0/2] fix rootfs extraction when paths already exist
@ 2025-12-01 17:13 Filip Schauer
  2025-12-01 17:13 ` [pve-devel] [PATCH proxmox 1/2] oci: " Filip Schauer
  2025-12-01 17:13 ` [pve-devel] [PATCH proxmox 2/2] oci: test replacing files in subsequent layers Filip Schauer
  0 siblings, 2 replies; 3+ messages in thread
From: Filip Schauer @ 2025-12-01 17:13 UTC (permalink / raw)
  To: pve-devel

Remove paths from previous layers that conflict with new layer entries
before unpacking. This aligns with the OCI spec. [0]

This fixes a rootfs extraction failure with docker.io/grafana/otel-lgtm,
which was reported in the Proxmox Forum [1].

[0] https://github.com/opencontainers/image-spec/blob/26647a49f642c7d22a1cd3aa0a48e4650a542269/layer.md#changeset-over-existing-files
[1] https://forum.proxmox.com/threads/otel-lgtm-oci-create-lxc-failed.176996/

Filip Schauer (2):
  oci: fix rootfs extraction when paths already exist
  oci: test replacing files in subsequent layers

 proxmox-oci/src/lib.rs                        |  20 ++++++
 proxmox-oci/tests/extract_replace.rs          |  57 ++++++++++++++++++
 .../oci_test_replace_dir_with_file.tar        | Bin 0 -> 8704 bytes
 .../oci_image_data/oci_test_replace_file.tar  | Bin 0 -> 8704 bytes
 .../oci_test_replace_file_with_dir.tar        | Bin 0 -> 8704 bytes
 5 files changed, 77 insertions(+)
 create mode 100644 proxmox-oci/tests/extract_replace.rs
 create mode 100644 proxmox-oci/tests/oci_image_data/oci_test_replace_dir_with_file.tar
 create mode 100644 proxmox-oci/tests/oci_image_data/oci_test_replace_file.tar
 create mode 100644 proxmox-oci/tests/oci_image_data/oci_test_replace_file_with_dir.tar

-- 
2.47.3



_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


^ permalink raw reply	[flat|nested] 3+ messages in thread

* [pve-devel] [PATCH proxmox 1/2] oci: fix rootfs extraction when paths already exist
  2025-12-01 17:13 [pve-devel] [PATCH proxmox 0/2] fix rootfs extraction when paths already exist Filip Schauer
@ 2025-12-01 17:13 ` Filip Schauer
  2025-12-01 17:13 ` [pve-devel] [PATCH proxmox 2/2] oci: test replacing files in subsequent layers Filip Schauer
  1 sibling, 0 replies; 3+ messages in thread
From: Filip Schauer @ 2025-12-01 17:13 UTC (permalink / raw)
  To: pve-devel

Remove paths from previous layers that conflict with new layer entries
before unpacking. This aligns with the OCI spec. [0]

This fixes a rootfs extraction failure with docker.io/grafana/otel-lgtm,
which was reported in the Proxmox Forum [1].

[0] https://github.com/opencontainers/image-spec/blob/26647a49f642c7d22a1cd3aa0a48e4650a542269/layer.md#changeset-over-existing-files
[1] https://forum.proxmox.com/threads/otel-lgtm-oci-create-lxc-failed.176996/

Signed-off-by: Filip Schauer <f.schauer@proxmox.com>
---
 proxmox-oci/src/lib.rs | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/proxmox-oci/src/lib.rs b/proxmox-oci/src/lib.rs
index cf0e4271..cce68207 100644
--- a/proxmox-oci/src/lib.rs
+++ b/proxmox-oci/src/lib.rs
@@ -302,6 +302,16 @@ fn extract_archive<R: Read, P: AsRef<Path>>(reader: &mut R, target_path: P) -> s
             }
         }
 
+        // If a file or directory already exists at this path, remove it first.
+        let file_path_abs = target_path.as_ref().join(file.path()?);
+        if file_path_abs.exists() {
+            if file_path_abs.is_dir() {
+                remove_dir_all(file_path_abs)?;
+            } else {
+                remove_file(file_path_abs)?;
+            }
+        }
+
         file.unpack_in(&target_path)?;
     }
 
@@ -309,6 +319,16 @@ fn extract_archive<R: Read, P: AsRef<Path>>(reader: &mut R, target_path: P) -> s
     // to avoid failure on restrictive parent directory permissions.
     directories.sort_by(|a, b| b.path_bytes().cmp(&a.path_bytes()));
     for mut dir in directories {
+        let dir_path_abs = target_path.as_ref().join(dir.path()?);
+
+        // Remove the trailing slash
+        let dir_path_abs = dir_path_abs.components().as_path();
+
+        // If a file already exists at this path, remove it first.
+        if dir_path_abs.exists() && !dir_path_abs.is_dir() {
+            remove_file(dir_path_abs)?;
+        }
+
         dir.unpack_in(&target_path)?;
     }
 
-- 
2.47.3



_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


^ permalink raw reply	[flat|nested] 3+ messages in thread

* [pve-devel] [PATCH proxmox 2/2] oci: test replacing files in subsequent layers
  2025-12-01 17:13 [pve-devel] [PATCH proxmox 0/2] fix rootfs extraction when paths already exist Filip Schauer
  2025-12-01 17:13 ` [pve-devel] [PATCH proxmox 1/2] oci: " Filip Schauer
@ 2025-12-01 17:13 ` Filip Schauer
  1 sibling, 0 replies; 3+ messages in thread
From: Filip Schauer @ 2025-12-01 17:13 UTC (permalink / raw)
  To: pve-devel

Add tests that verify later layer entries properly replace paths from
earlier layers.

Signed-off-by: Filip Schauer <f.schauer@proxmox.com>
---
 proxmox-oci/tests/extract_replace.rs          |  57 ++++++++++++++++++
 .../oci_test_replace_dir_with_file.tar        | Bin 0 -> 8704 bytes
 .../oci_image_data/oci_test_replace_file.tar  | Bin 0 -> 8704 bytes
 .../oci_test_replace_file_with_dir.tar        | Bin 0 -> 8704 bytes
 4 files changed, 57 insertions(+)
 create mode 100644 proxmox-oci/tests/extract_replace.rs
 create mode 100644 proxmox-oci/tests/oci_image_data/oci_test_replace_dir_with_file.tar
 create mode 100644 proxmox-oci/tests/oci_image_data/oci_test_replace_file.tar
 create mode 100644 proxmox-oci/tests/oci_image_data/oci_test_replace_file_with_dir.tar

diff --git a/proxmox-oci/tests/extract_replace.rs b/proxmox-oci/tests/extract_replace.rs
new file mode 100644
index 00000000..eb41f9e3
--- /dev/null
+++ b/proxmox-oci/tests/extract_replace.rs
@@ -0,0 +1,57 @@
+use std::fs::{read_to_string, remove_dir_all};
+
+use proxmox_oci::{parse_and_extract_image, Arch};
+use proxmox_sys::fs::make_tmp_dir;
+
+#[test]
+fn test_replace_file() {
+    let extract_dir = make_tmp_dir("/tmp/", None).unwrap();
+
+    parse_and_extract_image(
+        &"tests/oci_image_data/oci_test_replace_file.tar".into(),
+        &extract_dir,
+        Some(&Arch::Amd64),
+    )
+    .unwrap();
+
+    let replaced_path = extract_dir.join("etc/a");
+    assert!(replaced_path.is_file());
+    assert_eq!(read_to_string(replaced_path).unwrap(), "2");
+
+    // Cleanup
+    remove_dir_all(extract_dir).unwrap();
+}
+
+#[test]
+fn test_replace_file_with_dir() {
+    let extract_dir = make_tmp_dir("/tmp/", None).unwrap();
+
+    parse_and_extract_image(
+        &"tests/oci_image_data/oci_test_replace_file_with_dir.tar".into(),
+        &extract_dir,
+        Some(&Arch::Amd64),
+    )
+    .unwrap();
+
+    assert!(extract_dir.join("etc/a").is_dir());
+
+    // Cleanup
+    remove_dir_all(extract_dir).unwrap();
+}
+
+#[test]
+fn test_replace_dir_with_file() {
+    let extract_dir = make_tmp_dir("/tmp/", None).unwrap();
+
+    parse_and_extract_image(
+        &"tests/oci_image_data/oci_test_replace_dir_with_file.tar".into(),
+        &extract_dir,
+        Some(&Arch::Amd64),
+    )
+    .unwrap();
+
+    assert!(extract_dir.join("etc/a").is_file());
+
+    // Cleanup
+    remove_dir_all(extract_dir).unwrap();
+}
diff --git a/proxmox-oci/tests/oci_image_data/oci_test_replace_dir_with_file.tar b/proxmox-oci/tests/oci_image_data/oci_test_replace_dir_with_file.tar
new file mode 100644
index 0000000000000000000000000000000000000000..c4e488602eef13d5cee53710b97ffce5bf0586c7
GIT binary patch
literal 8704
zcmeHM&1+m$6n|QyVekvPu!!jJ7DcEtz26_fjUW-xO=)nU1i7D?C&^5hnS`b_P+h2K
z79#!uqM&R23oN*(I}xdi2trrlN_Q@b^}ILJn3;5Dsxt|dytjDo&3X5pd+xdC_q*qw
zv8yfHIh!2nh2WB$C;1bu;pcu??;Rt7MN;L5YE@tPMyG4q)oRjiwYuZRoAiBL-@Evm
zE!Mx&FocW43WI!6|K0jyLCW<%lBgM2|ELX7hz4(QjE-WC48cM>$A!}|Xb^I%i13jp
zB_y^0Qy-O%&`Mx53a|P43&w_Vf9p3QjO@Kb(*zO11WKytC_He?@&ELP^YgW@Yguwa
zN#bK<Q8CY`MZ{r+NidQyucF0_aYBrXNJfKLkd~|H;2AYj0^3OHz@y2_wU@4~e2P(W
zZ|D4Z^w533veUcYe{=Qc%g<l=<l4h0-u~hG$KR%NbMJn3<Hloe{WkyIBj-M<?A(0e
zi7yj!{g)rt*<UYSdFIsI=a;`o61DqNn#><X2ps1z2Jp`bV@xTFF!v!wZ#>7$M_68O
zDHlKj+zO?L3I^`ZAdLbt)*1yQpuHa9$cgxuco_eJl=vUv&Dn}`{I|c#@eiwv5Y`+i
z%_#QDD9?>l!f5zHsl>#{U;*xeMZ*mZR(c++h7Cb!>djR6-@WI9C3^DYbAPnnf9mGx
z#l;6J_p{B%Pwo8vr+l*Uz|K48P-PLA;n5_iTz#*dRA%dhW2|ie|Hf0~gEY~>)-JFE
zOe4#Q*DPx3uy<B_>?IR~TWJ`8U-BTN6tG=OhV2MH=J+3z|6xK8;GeM)|0BFPTk)kz
zwVHNZBdnQML%Wl;n(0E7Jey0`g3rv-)_MR*YS!0RGiSQc;Ou78*IO>DXKQ99)YnWi
zi=or4Z{jm=cA$UJ*|nN6TY;YW0C%pe*KI%*boSW_43L}AJE$xK#T4e0GptP@LSyQQ
zPyqr7Qqstb&chRXL9qymAdZ+ckh{o8onu0Y!p3~!*~NTzlyb0gyD)s!Y=Iv@_<CV@
z&-^=|K+zrS&)M+I%EfHGKh*7JG3|EykLvzBu*&DrpGmdv`opn(+M~ij+Xd;_4)^8C
zcFFLw#rY_01N=WNtVRqnf&UT5ayb7(f|uvN5$>F+xZr=&c8#nXTz8}0Bl|TkSb@;g
zwS(yfpK~ukgx4^sA-sg~0@4eJ*QpSM!f~Cw)@$C#I^9-#E2q!pf=*jGm8Pp%bK^p<
zMP5gXxv;-6bc+op?bB}Fr=ZFh-^e^P>#;D1`pgft2uGZx!Uiv`ih(o1p#~8VCC&?O
zh-X1K2{w^HwDlnn4|NP<yblb=eY{iDycP_TmPo^6aF~KVL;}{76X}sNoLUM=F{6|+
zDX7QJ2;&eWM3yNpky1V_EMA8D_WzN!vZfCg>iNDs)36#)R-FG1)_wOdPx(;(hoSNW
z^}n+IGvLNU`BC71ME=)L?EZT)blcRh5AdOkZrY>AK3w;5IwAVGP?=AR3mnMfYrws&
zjj?}zjMFgr+a&xWD)zVl+9n9_k6DTT$)26Q#ig`3#l2F5z}^Wk#dTCi>Gt&cOAVz5
ON)MDCC_Qj@df;!g^|Z$T

literal 0
HcmV?d00001

diff --git a/proxmox-oci/tests/oci_image_data/oci_test_replace_file.tar b/proxmox-oci/tests/oci_image_data/oci_test_replace_file.tar
new file mode 100644
index 0000000000000000000000000000000000000000..77922f7dbb6588a25e2b2514ec017d7327469d06
GIT binary patch
literal 8704
zcmeHMOK%)S5FQ8tYsE|CKolWZ%^^Yx-gNc5EiOpN5`s$<iv!3){j>+!yVma7iW4jW
z2cAA4#1BCH1O5S#I0R0JLoVUO32}lG93qA8*|p;}nYHomq9A4to>fg(b#+yL)%}&t
zTF3M*W;1<Id<0`zddKJR`=D&_8xRMcHQ7wP8XDj1^>w$|%(|UUf82aWeIKWLAAd7t
z{(Gw$Gd`<rkdpe(@(&!>`TtjT%}D++fRIKz!KHHsdl8hy-Un`p2S5T_K+?wn$V<b8
z4+a}a7-B}NAf>7B_=x-iCa_l%2KdJW0n3`G!roNH|8x9bYc!jA&#wA){kre=icULU
zXyO-=bltl`FKuu5D9QE4##&)@KMuIK)po6pEn3C8Uh%DU-7bRf^;=tT;q6}3FO_Yl
z9g3BxnI<^Cv4Pr%si^FVl{i6iV^F9Ts00c@JE;w2PAE%t+=?1g3Pcmeq`<@qh?|me
z#Dca86HbNJAp|2els=|~7gy8j2w~C7ozn3&y&dBag>ROQ58OZg0!sDhe=D9U7gnwo
z8^fvYwF-lDVAvAN4Kf0G4cZ3~iaTPRB$U~JAut8fsfa$$t@27SWQj6Da(&nIa2<eg
z>2$f0<}mcL@f~qVg(nz0<B;Jt_z<*mL^^O_ENH}})8K^%=@o&1m9boa5fpjHX|?Zh
z1<Q?{##BLG8>@=INd2EQsTGr?qRuJZtMP~52n61f4eLJ^>HM$je?>s2D1PqKxw*#I
z^F?+Fr;?SuI{(Vel`jEh5B4r!Mvp!83q619hi`8D^zKX7zqtAMsrP>T`SWk{)2Bc9
z>h|rY-uZRzyC*Jv*4VxC^0`|Ne6mE&oO$v0&PUJQIls90XyakJ_4L`@-~JTmRv+1Y
z{}O5}UVr}VlUert$9Mk7YIsjEhm)8Z!T+QOQiUTYz(1?;UlGhHixd94CH~7R%PjE!
z%qadFH$Lpv_@8nbPi$@k|C3&;E4)bfAIJY0h{NYUB{l!6h~{*~CI8c1yIS<U?QeDm
zWN&@%hMwE5*M092_reIXdBF1smH-xzT0pEtILDC$Q2IuBq0d)~Ucb}bPV{NHq*I+l
zrSi3+y?JFYBK6Ti5)O%Bza*IXkai`Vk}8GpR^j5X0Sk+wA@kEz7%Vgk-U5-qBkVyD
zhJ`~`GhzrrKnWpKaN@vft}Swk8Y-PYQn~}YqwIMt#6AaA0eQk46*3~gd4`--#866{
z3YY?=+<_9*IN`JfZWMNcXm7nCEH6D?j(>Oli>#$+JAb8>c>8qs)j@0J`TzI6?>^=U
zJJkOHV5q+T9}MBlewX;K=>H5GJ11|3+_N<_1o)wj&ZMo!1GpaabU05vorKD|pD<?k
z#6I49ti7GhvH$!SW8fH{j>118e7_dNu^Ec^2U_$0V}y3%A=mP<i~Cx+1@=3@IkZp<
X<vSCbuMN}@s3TBEppL+O8iBt6LZ+LJ

literal 0
HcmV?d00001

diff --git a/proxmox-oci/tests/oci_image_data/oci_test_replace_file_with_dir.tar b/proxmox-oci/tests/oci_image_data/oci_test_replace_file_with_dir.tar
new file mode 100644
index 0000000000000000000000000000000000000000..24743290414dc36a3cf3695b298b567932c5d812
GIT binary patch
literal 8704
zcmeHM&1)n@6mMOlVekw0;3A?!9~NPq+4}wnUIdAVUX~3Wlpyt)v?McOW)e2L238L$
znuCacfGFr${{k00tTz!^4-teti6^~zSX^IsPhv8g&aBQvR_s1>XI@pkdhb>Je)a0b
zu5@kxY;vp*f=6<m<X?D3zx!q7-xvujk|sY^tA@(g`vcQ!Hj`erJ2+~-aqUNqy@T6q
zvHtyKL%2AuZICbO-&=nyNWK35%C0%E{)ijPh{g&V7r6@>bBCQV+)#!PM>-mAtuhu<
z>6LOUNZ}Rb$T};G3KbTQS$|9@-sOZ6|AYv_lP0RrH&yZf9RHUZ&1Twn%VE{L9D4n%
z+ezn|<mp_x8hmCJHrE13QnR+Uk~uSg4rezyzTI_MJ6knNp}lH4Sq%L_djp?&y$|Dy
z!LHkh*%FM*C%AoO<*);)V6e}YV1nF?lBnjQ<*;c87J(2$v5zq*M{U%Baiy7J40A<I
zP!<VA1$7)__$`UkByj2q8*|6Ai@A4{a<Fo%Fnq;qLL5N&YGHV3{_Q(Z3<vw$aH^bH
zx|ppEr#j3FP8eefY{cA$7`^cvGam)E-cl}v)7%QBhzbVY&LE8fGS(UumDXPWrF!TG
zR=FQTPnyHfACK)(8=?>m-r^V?#T*$}4(%KVvt!U8<W>>kBT-67Y~e)rV0MIF0waE_
z?ShoH!+Wu@)tD;CYh_gtIKcmt!m47DG5n7>mZSWSnXLK0BAind7yNH}ZaEtSH(2kL
zWWVYKD-fExUND2;bM7UG@D?U5gcmTLLwXMJHWh+U0zCFg*?l?d54ye0oIV!|I_>6E
znyzG>^$TT>JdcjKaCk5biUTGc(r!Mcpvo9u%RF=|Sr|k^<~K}QA`OqhVX9(4Bw$TB
zksdk2sig>EMk!@dP!G9_Fb;XmEK^=0rTjkLDRSO9U@S+Rq{0R-EokISaA2y4C~;nJ
zLp%$@NpO+`qOA{scwjqYyblb=w6J&)-dq1g);fUyNe`rootfibFt&^F(JvzMko*tT
z_^$}(RK-ueKRes|qLn2lAngF`XpSI(f|N=b<++hc7!56yN=%FlkYX{x;2L0Pu+sBj
zHJtKFQ*ZK&CwZ~;!nLK3F-q?4pFfWtxaVhfdgt4(uKsxW*()Did+@}Y-(COk>vU%3
z?N4spc;t;=X1{sp+y{;Ao6kMAbJu$d^yJBBe(S#b#Ld(5^Y=IIWgCy4+Wz%-`S|jE
z+i#sijrl82oq9M)8du-xC3SW%txa$M|C1(l6-JH4KO?)GkatZGaIL8EUlGmeigWz8
zzRdBjB!PPri;8(hEg}xe03^VjiFp+*W{ksK%S9xkL2&W6T*bTq0ED1`AR?Iv|DPx1
z`cL1lu|J*%l+S#6`LiTZJ3pk!>~y`YwT(s~>-cb?o!{F>Tc-EB!2hjv-#yGzK63tJ
zxK2X-ude@0Zw;z675RTf{byL%`RB!uLrX)$1b?KWGim8@UtV9<bc7hzLh5=#)!OHB
zsN=QZ?$upC@}D0^X&B!&4*!UXJuWEDf51OxHU7s(cJdyV(xQs{Qn3a0D!?gjqc%#n
VCf8qUs3TBEppHNtfjct-e*)yOwi^Hd

literal 0
HcmV?d00001

-- 
2.47.3



_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2025-12-01 17:13 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-12-01 17:13 [pve-devel] [PATCH proxmox 0/2] fix rootfs extraction when paths already exist Filip Schauer
2025-12-01 17:13 ` [pve-devel] [PATCH proxmox 1/2] oci: " Filip Schauer
2025-12-01 17:13 ` [pve-devel] [PATCH proxmox 2/2] oci: test replacing files in subsequent layers Filip Schauer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal