From 7fa80e848b515255c81d9acc169409616bff04e9 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Fri, 2 Oct 2026 21:12:13 -0700 Subject: [PATCH 1/3] Fix file_mode and dir_mode descriptions --- .github/workflows/inttest.yml | 4 ++-- examples/unpackerr.conf.example | 17 +++++++++++++---- frontend/src/lib/i18n/locales/el.json | 8 ++++---- frontend/src/lib/i18n/locales/en.json | 8 ++++---- frontend/src/lib/i18n/locales/es.json | 8 ++++---- frontend/src/lib/i18n/locales/nl.json | 8 ++++---- go.mod | 2 +- go.sum | 4 ++-- pkg/configdef/definitions.yml | 17 +++++++++++++---- 9 files changed, 47 insertions(+), 29 deletions(-) diff --git a/.github/workflows/inttest.yml b/.github/workflows/inttest.yml index 820aa447..443f4a61 100644 --- a/.github/workflows/inttest.yml +++ b/.github/workflows/inttest.yml @@ -20,8 +20,8 @@ jobs: go-version-file: go.mod - name: Install archive tools run: | - sudo apt-get update - sudo apt-get install -y rar p7zip-full zip unzip + sudo apt update + sudo apt install -y rar p7zip-full zip unzip - name: Build unpackerr run: go build -o unpackerr . - name: Clone integration tests diff --git a/examples/unpackerr.conf.example b/examples/unpackerr.conf.example index 8a9c96eb..8bdd5211 100644 --- a/examples/unpackerr.conf.example +++ b/examples/unpackerr.conf.example @@ -96,9 +96,18 @@ remnant_action = "rename" ## Do not wrap the number in quotes. Raise this only if you have fast disks and CPU. parallel = 1 -## Use these configurations to control the file modes used for newly extracted -## files and folders. Recommend 0644/0755 or 0666/0777. +## When an archive stores a file mode, the group and other bits from +## this setting are added to it. Owner bits and the executable bit stay +## with the archive. Entries that store no mode are created with this +## mode. The process umask still applies, so 0666 becomes 0644 under +## umask 0022. Use 0644, or 0660 or 0666 when another user must write +## the extracted files. file_mode = "0644" + +## When an archive stores a directory mode, the group and other bits +## from this setting are added to it. Owner rwx is always kept. +## Directories that store no mode are created with this mode. The +## process umask still applies. dir_mode = "0755" ## List of passwords to use for encrypted archives. Must be a list of strings. @@ -185,7 +194,7 @@ passwords = [] ## The following sections can be repeated if you have more than one Sonarr, ## ## Radarr, Lidarr, Readarr, Folder, Webhook, and/or Command Hook. ## ## Identify each instance with a short key: [sonarr.uhd], [folder.tv]. ## -## Changed in v1.0.0 (September 2026): map keys, not [[array]] list rows. ## +## Changed in v1.0.0 (October 2026): map keys, not [[array]] list rows. ## ## You MUST uncomment the [header.0], url and api_key for any Starr app. ## ## Uncomment [sonarr.0], [radarr.0], [lidarr.0], and/or [readarr.0] plus the ## ## url and api_key if that app is in use. ## @@ -547,4 +556,4 @@ passwords = [] ## You can adjust how long to wait for the command to run. # timeout = "10s" -## => Content Auto Generated, 30 SEP 2026 07:06 UTC +## => Content Auto Generated, 03 OCT 2026 04:10 UTC diff --git a/frontend/src/lib/i18n/locales/el.json b/frontend/src/lib/i18n/locales/el.json index 227d4e95..0b3ccff8 100644 --- a/frontend/src/lib/i18n/locales/el.json +++ b/frontend/src/lib/i18n/locales/el.json @@ -523,13 +523,13 @@ }, "fileMode": { "label": "Δικαιώματα αρχείων", - "description": "Δικαιώματα για νέα εξαγμένα αρχεία.", - "tooltip": "Μόνο Unix. Αγνοείται στα Windows." + "description": "Bits ομάδας και άλλων που προστίθενται στα εξαγμένα αρχεία.", + "tooltip": "Μόνο Unix. Προστίθενται σε δικαιώματα αποθηκευμένα στο αρχείο. Τα bits κατόχου μένουν όπως στο αρχείο. Η umask της διεργασίας εξακολουθεί να ισχύει. Αγνοείται στα Windows." }, "dirMode": { "label": "Δικαιώματα φακέλων", - "description": "Δικαιώματα για νέους εξαγμένους φακέλους.", - "tooltip": "Μόνο Unix. Αγνοείται στα Windows." + "description": "Bits ομάδας και άλλων που προστίθενται στους εξαγμένους φακέλους.", + "tooltip": "Μόνο Unix. Προστίθενται σε δικαιώματα φακέλου αποθηκευμένα στο αρχείο. Ο κάτοχος διατηρεί πάντα rwx. Η umask της διεργασίας εξακολουθεί να ισχύει. Αγνοείται στα Windows." }, "logFile": { "label": "Αρχείο καταγραφής", diff --git a/frontend/src/lib/i18n/locales/en.json b/frontend/src/lib/i18n/locales/en.json index b988fc52..18b66dba 100644 --- a/frontend/src/lib/i18n/locales/en.json +++ b/frontend/src/lib/i18n/locales/en.json @@ -523,13 +523,13 @@ }, "fileMode": { "label": "File mode", - "description": "Permissions for newly extracted files.", - "tooltip": "Unix only. Ignored on Windows." + "description": "Group and other bits added to extracted files.", + "tooltip": "Unix only. Added to a mode stored in the archive. Owner bits stay with the archive. The process umask still applies. Ignored on Windows." }, "dirMode": { "label": "Dir mode", - "description": "Permissions for newly extracted folders.", - "tooltip": "Unix only. Ignored on Windows." + "description": "Group and other bits added to extracted folders.", + "tooltip": "Unix only. Added to a directory mode stored in the archive. Owner rwx is always kept. The process umask still applies. Ignored on Windows." }, "logFile": { "label": "Log file", diff --git a/frontend/src/lib/i18n/locales/es.json b/frontend/src/lib/i18n/locales/es.json index 62f2aec7..f625573f 100644 --- a/frontend/src/lib/i18n/locales/es.json +++ b/frontend/src/lib/i18n/locales/es.json @@ -523,13 +523,13 @@ }, "fileMode": { "label": "Modo de archivo", - "description": "Permisos para archivos extraídos nuevos.", - "tooltip": "Solo Unix. Se ignora en Windows." + "description": "Bits de grupo y de otros que se añaden a los archivos extraídos.", + "tooltip": "Solo Unix. Se añaden a un modo guardado en el archivo. Los bits del propietario se quedan como en el archivo. La umask del proceso sigue aplicando. Se ignora en Windows." }, "dirMode": { "label": "Modo de carpeta", - "description": "Permisos para carpetas extraídas nuevas.", - "tooltip": "Solo Unix. Se ignora en Windows." + "description": "Bits de grupo y de otros que se añaden a las carpetas extraídas.", + "tooltip": "Solo Unix. Se añaden a un modo de carpeta guardado en el archivo. El propietario siempre conserva rwx. La umask del proceso sigue aplicando. Se ignora en Windows." }, "logFile": { "label": "Archivo de registro", diff --git a/frontend/src/lib/i18n/locales/nl.json b/frontend/src/lib/i18n/locales/nl.json index 60634ccb..7370d366 100644 --- a/frontend/src/lib/i18n/locales/nl.json +++ b/frontend/src/lib/i18n/locales/nl.json @@ -523,13 +523,13 @@ }, "fileMode": { "label": "Bestandsmodus", - "description": "Rechten voor nieuw uitgepakte bestanden.", - "tooltip": "Alleen Unix. Wordt op Windows genegeerd." + "description": "Groeps- en overige bits die aan uitgepakte bestanden worden toegevoegd.", + "tooltip": "Alleen Unix. Worden toegevoegd aan een modus uit het archief. Eigenaarsbits blijven van het archief. De umask van het proces geldt nog. Wordt op Windows genegeerd." }, "dirMode": { "label": "Mapmodus", - "description": "Rechten voor nieuw uitgepakte mappen.", - "tooltip": "Alleen Unix. Wordt op Windows genegeerd." + "description": "Groeps- en overige bits die aan uitgepakte mappen worden toegevoegd.", + "tooltip": "Alleen Unix. Worden toegevoegd aan een mapmodus uit het archief. De eigenaar houdt altijd rwx. De umask van het proces geldt nog. Wordt op Windows genegeerd." }, "logFile": { "label": "Logbestand", diff --git a/go.mod b/go.mod index f8bb8a9e..fcf34db5 100644 --- a/go.mod +++ b/go.mod @@ -24,7 +24,7 @@ require ( golift.io/rotatorr v0.1.0 golift.io/starr v1.4.1 golift.io/version v0.0.2 - golift.io/xtractr v0.7.1-0.20261001061402-3616e46c087b + golift.io/xtractr v0.7.1-0.20261003040632-5b2947ec1a62 gopkg.in/yaml.v3 v3.0.1 ) diff --git a/go.sum b/go.sum index 3fb70ca6..622ebfea 100644 --- a/go.sum +++ b/go.sum @@ -180,8 +180,8 @@ golift.io/udf v0.1.0 h1:arzc1C6Ko9MR2lvpZuZ1WXceGkUxsTOvxg3NIiX6iiA= golift.io/udf v0.1.0/go.mod h1:rw8k1sEHRzKZJCgBFfSPolPb0CpyS0apwoeOwwQQM6o= golift.io/version v0.0.2 h1:i0gXRuSDHKs4O0sVDUg4+vNIuOxYoXhaxspftu2FRTE= golift.io/version v0.0.2/go.mod h1:76aHNz8/Pm7CbuxIsDi97jABL5Zui3f2uZxDm4vB6hU= -golift.io/xtractr v0.7.1-0.20261001061402-3616e46c087b h1:uI2CQFtkBE4Boh3iIm703IafdtlGtUAITAkWv1lOFmU= -golift.io/xtractr v0.7.1-0.20261001061402-3616e46c087b/go.mod h1:my82SdhkWFM+6jGnWoxEhKxtcGUmeYsAzmiw2Ku90sE= +golift.io/xtractr v0.7.1-0.20261003040632-5b2947ec1a62 h1:+EU2KMF8MhPNStDBEYG7b1dTxoK0X9kvvafI30bjOR0= +golift.io/xtractr v0.7.1-0.20261003040632-5b2947ec1a62/go.mod h1:mGuJ4E+lIyi0nslw3XabGwIrqRYznMk9KASXcTbTCQI= google.golang.org/protobuf v1.36.12 h1:pJOKDDOyeXErUroCihFAd5LQuwXBSpVnKGrj5o/fwxc= google.golang.org/protobuf v1.36.12/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= diff --git a/pkg/configdef/definitions.yml b/pkg/configdef/definitions.yml index 353909f6..51887110 100644 --- a/pkg/configdef/definitions.yml +++ b/pkg/configdef/definitions.yml @@ -409,10 +409,14 @@ sections: envvar: FILE_MODE default: '0644' recommend: *FILE_MODES - short: Extracted files are written with this mode. + short: Group and other bits added to extracted files. desc: | - Use these configurations to control the file modes used for newly extracted - files and folders. Recommend 0644/0755 or 0666/0777. + When an archive stores a file mode, the group and other bits from + this setting are added to it. Owner bits and the executable bit stay + with the archive. Entries that store no mode are created with this + mode. The process umask still applies, so 0666 becomes 0644 under + umask 0022. Use 0644, or 0660 or 0666 when another user must write + the extracted files. - name: dir_mode envvar: DIR_MODE default: '0755' @@ -423,7 +427,12 @@ sections: - value: '0770' - value: '0775' - value: '0777' - short: Extracted folders are written with this mode + short: Group and other bits added to extracted folders. + desc: | + When an archive stores a directory mode, the group and other bits + from this setting are added to it. Owner rwx is always kept. + Directories that store no mode are created with this mode. The + process umask still applies. - name: passwords envvar: PASSWORD_ default: [] From 2a7210a9d37f8d5465a1ede41e6db5a9c5e34a67 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Sat, 3 Oct 2026 18:52:42 -0700 Subject: [PATCH 2/3] Update file_mode and dir_mode descriptions --- examples/unpackerr.conf.example | 20 +++++++++----------- frontend/src/lib/i18n/locales/el.json | 8 ++++---- frontend/src/lib/i18n/locales/en.json | 8 ++++---- frontend/src/lib/i18n/locales/es.json | 8 ++++---- frontend/src/lib/i18n/locales/nl.json | 8 ++++---- go.mod | 2 +- go.sum | 4 ++-- pkg/configdef/definitions.yml | 22 ++++++++++------------ 8 files changed, 38 insertions(+), 42 deletions(-) diff --git a/examples/unpackerr.conf.example b/examples/unpackerr.conf.example index 8bdd5211..bc797111 100644 --- a/examples/unpackerr.conf.example +++ b/examples/unpackerr.conf.example @@ -96,18 +96,16 @@ remnant_action = "rename" ## Do not wrap the number in quotes. Raise this only if you have fast disks and CPU. parallel = 1 -## When an archive stores a file mode, the group and other bits from -## this setting are added to it. Owner bits and the executable bit stay -## with the archive. Entries that store no mode are created with this -## mode. The process umask still applies, so 0666 becomes 0644 under -## umask 0022. Use 0644, or 0660 or 0666 when another user must write -## the extracted files. +## Extracted files are created with this mode. An execute bit stored in +## the archive is kept for owner, group, or other only when this mode +## already grants that class access, so 0644 beside an archived 0755 +## stays executable and 0660 beside 0755 becomes 0770. The process +## umask still applies, so 0666 becomes 0644 under umask 0022. Use +## 0644, or 0660 or 0666 when another user must write the extracted files. file_mode = "0644" -## When an archive stores a directory mode, the group and other bits -## from this setting are added to it. Owner rwx is always kept. -## Directories that store no mode are created with this mode. The -## process umask still applies. +## Extracted directories are created with this mode. The process umask +## still applies. dir_mode = "0755" ## List of passwords to use for encrypted archives. Must be a list of strings. @@ -556,4 +554,4 @@ passwords = [] ## You can adjust how long to wait for the command to run. # timeout = "10s" -## => Content Auto Generated, 03 OCT 2026 04:10 UTC +## => Content Auto Generated, 04 OCT 2026 01:51 UTC diff --git a/frontend/src/lib/i18n/locales/el.json b/frontend/src/lib/i18n/locales/el.json index 0b3ccff8..bef388f9 100644 --- a/frontend/src/lib/i18n/locales/el.json +++ b/frontend/src/lib/i18n/locales/el.json @@ -523,13 +523,13 @@ }, "fileMode": { "label": "Δικαιώματα αρχείων", - "description": "Bits ομάδας και άλλων που προστίθενται στα εξαγμένα αρχεία.", - "tooltip": "Μόνο Unix. Προστίθενται σε δικαιώματα αποθηκευμένα στο αρχείο. Τα bits κατόχου μένουν όπως στο αρχείο. Η umask της διεργασίας εξακολουθεί να ισχύει. Αγνοείται στα Windows." + "description": "Δικαιώματα για εξαγμένα αρχεία. Τα bits εκτέλεσης του αρχείου διατηρούνται.", + "tooltip": "Μόνο Unix. Ένα bit εκτέλεσης από το αρχείο διατηρείται για κάτοχο, ομάδα ή άλλους μόνο όταν αυτή η λειτουργία δίνει ήδη πρόσβαση σε αυτή την κλάση. Η umask της διεργασίας εξακολουθεί να ισχύει. Αγνοείται στα Windows." }, "dirMode": { "label": "Δικαιώματα φακέλων", - "description": "Bits ομάδας και άλλων που προστίθενται στους εξαγμένους φακέλους.", - "tooltip": "Μόνο Unix. Προστίθενται σε δικαιώματα φακέλου αποθηκευμένα στο αρχείο. Ο κάτοχος διατηρεί πάντα rwx. Η umask της διεργασίας εξακολουθεί να ισχύει. Αγνοείται στα Windows." + "description": "Δικαιώματα για εξαγμένους φακέλους.", + "tooltip": "Μόνο Unix. Οι εξαγμένοι φάκελοι δημιουργούνται με αυτή τη λειτουργία. Η umask της διεργασίας εξακολουθεί να ισχύει. Αγνοείται στα Windows." }, "logFile": { "label": "Αρχείο καταγραφής", diff --git a/frontend/src/lib/i18n/locales/en.json b/frontend/src/lib/i18n/locales/en.json index 18b66dba..7d9131d2 100644 --- a/frontend/src/lib/i18n/locales/en.json +++ b/frontend/src/lib/i18n/locales/en.json @@ -523,13 +523,13 @@ }, "fileMode": { "label": "File mode", - "description": "Group and other bits added to extracted files.", - "tooltip": "Unix only. Added to a mode stored in the archive. Owner bits stay with the archive. The process umask still applies. Ignored on Windows." + "description": "Mode for extracted files. Archive execute bits are kept.", + "tooltip": "Unix only. An execute bit stored in the archive is kept for owner, group, or other only when this mode already grants that class access. Umask still applies. Ignored on Windows." }, "dirMode": { "label": "Dir mode", - "description": "Group and other bits added to extracted folders.", - "tooltip": "Unix only. Added to a directory mode stored in the archive. Owner rwx is always kept. The process umask still applies. Ignored on Windows." + "description": "Mode for extracted folders.", + "tooltip": "Unix only. Extracted folders are created with this mode. Umask still applies. Ignored on Windows." }, "logFile": { "label": "Log file", diff --git a/frontend/src/lib/i18n/locales/es.json b/frontend/src/lib/i18n/locales/es.json index f625573f..78a478e1 100644 --- a/frontend/src/lib/i18n/locales/es.json +++ b/frontend/src/lib/i18n/locales/es.json @@ -523,13 +523,13 @@ }, "fileMode": { "label": "Modo de archivo", - "description": "Bits de grupo y de otros que se añaden a los archivos extraídos.", - "tooltip": "Solo Unix. Se añaden a un modo guardado en el archivo. Los bits del propietario se quedan como en el archivo. La umask del proceso sigue aplicando. Se ignora en Windows." + "description": "Modo de los archivos extraídos. Se conservan los bits de ejecución del archivo.", + "tooltip": "Solo Unix. Un bit de ejecución guardado en el archivo se conserva para propietario, grupo u otros solo si este modo ya concede acceso a esa clase. La umask del proceso sigue aplicando. Se ignora en Windows." }, "dirMode": { "label": "Modo de carpeta", - "description": "Bits de grupo y de otros que se añaden a las carpetas extraídas.", - "tooltip": "Solo Unix. Se añaden a un modo de carpeta guardado en el archivo. El propietario siempre conserva rwx. La umask del proceso sigue aplicando. Se ignora en Windows." + "description": "Modo de las carpetas extraídas.", + "tooltip": "Solo Unix. Las carpetas extraídas se crean con este modo. La umask del proceso sigue aplicando. Se ignora en Windows." }, "logFile": { "label": "Archivo de registro", diff --git a/frontend/src/lib/i18n/locales/nl.json b/frontend/src/lib/i18n/locales/nl.json index 7370d366..7dfa7a8b 100644 --- a/frontend/src/lib/i18n/locales/nl.json +++ b/frontend/src/lib/i18n/locales/nl.json @@ -523,13 +523,13 @@ }, "fileMode": { "label": "Bestandsmodus", - "description": "Groeps- en overige bits die aan uitgepakte bestanden worden toegevoegd.", - "tooltip": "Alleen Unix. Worden toegevoegd aan een modus uit het archief. Eigenaarsbits blijven van het archief. De umask van het proces geldt nog. Wordt op Windows genegeerd." + "description": "Modus voor uitgepakte bestanden. Uitvoerbits uit het archief blijven behouden.", + "tooltip": "Alleen Unix. Een uitvoerbit uit het archief blijft alleen staan voor eigenaar, groep of anderen als deze modus die klasse al toegang geeft. De umask van het proces geldt nog. Wordt op Windows genegeerd." }, "dirMode": { "label": "Mapmodus", - "description": "Groeps- en overige bits die aan uitgepakte mappen worden toegevoegd.", - "tooltip": "Alleen Unix. Worden toegevoegd aan een mapmodus uit het archief. De eigenaar houdt altijd rwx. De umask van het proces geldt nog. Wordt op Windows genegeerd." + "description": "Modus voor uitgepakte mappen.", + "tooltip": "Alleen Unix. Uitgepakte mappen krijgen deze modus. De umask van het proces geldt nog. Wordt op Windows genegeerd." }, "logFile": { "label": "Logbestand", diff --git a/go.mod b/go.mod index fcf34db5..2a148031 100644 --- a/go.mod +++ b/go.mod @@ -24,7 +24,7 @@ require ( golift.io/rotatorr v0.1.0 golift.io/starr v1.4.1 golift.io/version v0.0.2 - golift.io/xtractr v0.7.1-0.20261003040632-5b2947ec1a62 + golift.io/xtractr v0.7.1-0.20261004014820-a77e5040698a gopkg.in/yaml.v3 v3.0.1 ) diff --git a/go.sum b/go.sum index 622ebfea..c569cf5c 100644 --- a/go.sum +++ b/go.sum @@ -180,8 +180,8 @@ golift.io/udf v0.1.0 h1:arzc1C6Ko9MR2lvpZuZ1WXceGkUxsTOvxg3NIiX6iiA= golift.io/udf v0.1.0/go.mod h1:rw8k1sEHRzKZJCgBFfSPolPb0CpyS0apwoeOwwQQM6o= golift.io/version v0.0.2 h1:i0gXRuSDHKs4O0sVDUg4+vNIuOxYoXhaxspftu2FRTE= golift.io/version v0.0.2/go.mod h1:76aHNz8/Pm7CbuxIsDi97jABL5Zui3f2uZxDm4vB6hU= -golift.io/xtractr v0.7.1-0.20261003040632-5b2947ec1a62 h1:+EU2KMF8MhPNStDBEYG7b1dTxoK0X9kvvafI30bjOR0= -golift.io/xtractr v0.7.1-0.20261003040632-5b2947ec1a62/go.mod h1:mGuJ4E+lIyi0nslw3XabGwIrqRYznMk9KASXcTbTCQI= +golift.io/xtractr v0.7.1-0.20261004014820-a77e5040698a h1:QHFNLAEHDLhCINsjbgOCQ5s66wNv8d/fnPdgwxF7KtQ= +golift.io/xtractr v0.7.1-0.20261004014820-a77e5040698a/go.mod h1:mGuJ4E+lIyi0nslw3XabGwIrqRYznMk9KASXcTbTCQI= google.golang.org/protobuf v1.36.12 h1:pJOKDDOyeXErUroCihFAd5LQuwXBSpVnKGrj5o/fwxc= google.golang.org/protobuf v1.36.12/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= diff --git a/pkg/configdef/definitions.yml b/pkg/configdef/definitions.yml index 51887110..70cce396 100644 --- a/pkg/configdef/definitions.yml +++ b/pkg/configdef/definitions.yml @@ -409,14 +409,14 @@ sections: envvar: FILE_MODE default: '0644' recommend: *FILE_MODES - short: Group and other bits added to extracted files. + short: Mode for extracted files. Archive execute bits are kept. desc: | - When an archive stores a file mode, the group and other bits from - this setting are added to it. Owner bits and the executable bit stay - with the archive. Entries that store no mode are created with this - mode. The process umask still applies, so 0666 becomes 0644 under - umask 0022. Use 0644, or 0660 or 0666 when another user must write - the extracted files. + Extracted files are created with this mode. An execute bit stored in + the archive is kept for owner, group, or other only when this mode + already grants that class access, so 0644 beside an archived 0755 + stays executable and 0660 beside 0755 becomes 0770. The process + umask still applies, so 0666 becomes 0644 under umask 0022. Use + 0644, or 0660 or 0666 when another user must write the extracted files. - name: dir_mode envvar: DIR_MODE default: '0755' @@ -427,12 +427,10 @@ sections: - value: '0770' - value: '0775' - value: '0777' - short: Group and other bits added to extracted folders. + short: Mode for extracted folders. desc: | - When an archive stores a directory mode, the group and other bits - from this setting are added to it. Owner rwx is always kept. - Directories that store no mode are created with this mode. The - process umask still applies. + Extracted directories are created with this mode. The process umask + still applies. - name: passwords envvar: PASSWORD_ default: [] From d485397489144fe110a14851dc17bd4414a7d229 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Sun, 4 Oct 2026 01:31:30 -0700 Subject: [PATCH 3/3] Add preserve mode to folders --- examples/docker-compose.yml | 3 ++- examples/unpackerr.conf.example | 19 +++++++++------ frontend/src/lib/i18n/locales/el.json | 9 +++++-- frontend/src/lib/i18n/locales/en.json | 9 +++++-- frontend/src/lib/i18n/locales/es.json | 9 +++++-- frontend/src/lib/i18n/locales/nl.json | 9 +++++-- frontend/src/lib/slug.ts | 1 + frontend/src/lib/types.ts | 1 + .../src/pages/settings/FoldersForm.svelte | 13 ++++++++++ go.mod | 2 +- go.sum | 4 ++-- pkg/configdef/definitions.yml | 24 +++++++++++++------ pkg/folders/config.go | 1 + pkg/unpackerr/configdump.go | 8 +++---- pkg/unpackerr/folder.go | 1 + pkg/unpackerr/openapi.json | 1 + 16 files changed, 84 insertions(+), 30 deletions(-) diff --git a/examples/docker-compose.yml b/examples/docker-compose.yml index ed80e86b..e26384f9 100644 --- a/examples/docker-compose.yml +++ b/examples/docker-compose.yml @@ -142,6 +142,7 @@ services: - UN_FOLDER_0_DISABLE_LOG=false - UN_FOLDER_0_MOVE_BACK=false - UN_FOLDER_0_EXTRACT_ISOS=false + - UN_FOLDER_0_PRESERVE_EXEC=false - UN_FOLDER_0_SKIP_EMPTY=false ## Hook Payload ## Webhooks @@ -174,4 +175,4 @@ services: - UN_CMDHOOK_0_EXCLUDE_1=lidarr - UN_CMDHOOK_0_TIMEOUT=10s -## => Content Auto Generated, 30 SEP 2026 07:06 UTC +## => Content Auto Generated, 04 OCT 2026 06:03 UTC diff --git a/examples/unpackerr.conf.example b/examples/unpackerr.conf.example index bc797111..48026144 100644 --- a/examples/unpackerr.conf.example +++ b/examples/unpackerr.conf.example @@ -96,12 +96,11 @@ remnant_action = "rename" ## Do not wrap the number in quotes. Raise this only if you have fast disks and CPU. parallel = 1 -## Extracted files are created with this mode. An execute bit stored in -## the archive is kept for owner, group, or other only when this mode -## already grants that class access, so 0644 beside an archived 0755 -## stays executable and 0660 beside 0755 becomes 0770. The process -## umask still applies, so 0666 becomes 0644 under umask 0022. Use -## 0644, or 0660 or 0666 when another user must write the extracted files. +## Extracted files are created with this mode. The process umask still +## applies, so 0666 becomes 0644 under umask 0022. Use 0644, or 0660 or +## 0666 when another user must write the extracted files. Archive +## execute bits are kept only for a watched folder with preserve_exec +## enabled. file_mode = "0644" ## Extracted directories are created with this mode. The process umask @@ -450,6 +449,12 @@ passwords = [] # move_back = false ## Set this to true if you want this app to extract ISO files with .iso extension. # extract_isos = false +## When true, an execute bit stored in the archive is kept for owner, +## group, or other only when file_mode already grants that class access. +## A 6 beside an archived 7 becomes 7, a 4 becomes 5, and a 0 stays 0. +## Off, extracted files use file_mode only. Starr extracts stay off. +## The process umask still applies. +# preserve_exec = false ## Incomplete-download suffixes such as `.part` or `.crdownload`. Extraction ## stays in waiting as long as any matching file is in the watched item's ## top folder. Subfolders are not scanned. The UI and config always store @@ -554,4 +559,4 @@ passwords = [] ## You can adjust how long to wait for the command to run. # timeout = "10s" -## => Content Auto Generated, 04 OCT 2026 01:51 UTC +## => Content Auto Generated, 04 OCT 2026 06:03 UTC diff --git a/frontend/src/lib/i18n/locales/el.json b/frontend/src/lib/i18n/locales/el.json index bef388f9..bfa49fd2 100644 --- a/frontend/src/lib/i18n/locales/el.json +++ b/frontend/src/lib/i18n/locales/el.json @@ -523,8 +523,8 @@ }, "fileMode": { "label": "Δικαιώματα αρχείων", - "description": "Δικαιώματα για εξαγμένα αρχεία. Τα bits εκτέλεσης του αρχείου διατηρούνται.", - "tooltip": "Μόνο Unix. Ένα bit εκτέλεσης από το αρχείο διατηρείται για κάτοχο, ομάδα ή άλλους μόνο όταν αυτή η λειτουργία δίνει ήδη πρόσβαση σε αυτή την κλάση. Η umask της διεργασίας εξακολουθεί να ισχύει. Αγνοείται στα Windows." + "description": "Δικαιώματα για εξαγμένα αρχεία.", + "tooltip": "Μόνο Unix. Τα εξαγμένα αρχεία δημιουργούνται με αυτή τη λειτουργία. Η umask της διεργασίας εξακολουθεί να ισχύει. Αγνοείται στα Windows." }, "dirMode": { "label": "Δικαιώματα φακέλων", @@ -797,6 +797,11 @@ "description": "Τα αρχεία .iso αντιμετωπίζονται ως αρχειοθήκες.", "tooltip": "Ανενεργό αγνοεί εικόνες ISO. Ενεργοποιήστε το μόνο αν θέλετε πραγματικά να αποσυμπιεστούν." }, + "preserve_exec": { + "label": "Διατήρηση bits εκτέλεσης", + "description": "Διατήρηση των bits εκτέλεσης του αρχείου.", + "tooltip": "Ανενεργό, τα εξαγμένα αρχεία παίρνουν μόνο τα δικαιώματα αρχείων. Ενεργό, ένα bit εκτέλεσης από το αρχείο διατηρείται για κάτοχο, ομάδα ή άλλους όταν τα δικαιώματα αρχείων δίνουν ήδη πρόσβαση σε αυτή την κλάση. Οι εξαγωγές Starr μένουν ανενεργές." + }, "disableRecursion": { "label": "Αναδρομή", "description": "Εξαγωγή αρχειοθηκών μέσα σε άλλες αρχειοθήκες.", diff --git a/frontend/src/lib/i18n/locales/en.json b/frontend/src/lib/i18n/locales/en.json index 7d9131d2..08152a28 100644 --- a/frontend/src/lib/i18n/locales/en.json +++ b/frontend/src/lib/i18n/locales/en.json @@ -523,8 +523,8 @@ }, "fileMode": { "label": "File mode", - "description": "Mode for extracted files. Archive execute bits are kept.", - "tooltip": "Unix only. An execute bit stored in the archive is kept for owner, group, or other only when this mode already grants that class access. Umask still applies. Ignored on Windows." + "description": "Mode for extracted files.", + "tooltip": "Unix only. Extracted files are created with this mode. Umask still applies. Ignored on Windows." }, "dirMode": { "label": "Dir mode", @@ -797,6 +797,11 @@ "description": "Treat .iso files as archives.", "tooltip": "Off ignores ISO images. Turn this on only if you really want them unpacked." }, + "preserve_exec": { + "label": "Keep execute bits", + "description": "Keep execute bits stored in the archive.", + "tooltip": "Off, extracted files use File mode only. On, an archived execute bit is kept for owner, group, or other when File mode already grants that class access. Starr extracts stay off." + }, "disableRecursion": { "label": "Recursion", "description": "Extract archives found inside other archives.", diff --git a/frontend/src/lib/i18n/locales/es.json b/frontend/src/lib/i18n/locales/es.json index 78a478e1..ff65f3a3 100644 --- a/frontend/src/lib/i18n/locales/es.json +++ b/frontend/src/lib/i18n/locales/es.json @@ -523,8 +523,8 @@ }, "fileMode": { "label": "Modo de archivo", - "description": "Modo de los archivos extraídos. Se conservan los bits de ejecución del archivo.", - "tooltip": "Solo Unix. Un bit de ejecución guardado en el archivo se conserva para propietario, grupo u otros solo si este modo ya concede acceso a esa clase. La umask del proceso sigue aplicando. Se ignora en Windows." + "description": "Modo de los archivos extraídos.", + "tooltip": "Solo Unix. Los archivos extraídos se crean con este modo. La umask del proceso sigue aplicando. Se ignora en Windows." }, "dirMode": { "label": "Modo de carpeta", @@ -797,6 +797,11 @@ "description": "Tratar los archivos .iso como archivos comprimidos.", "tooltip": "Apagado ignora las imágenes ISO. Actívalo solo si de verdad quieres desempaquetarlas." }, + "preserve_exec": { + "label": "Conservar bits de ejecución", + "description": "Conservar los bits de ejecución del archivo.", + "tooltip": "Apagado, los archivos extraídos usan solo el modo de archivo. Encendido, un bit de ejecución del archivo se conserva para propietario, grupo u otros si el modo de archivo ya concede acceso a esa clase. Las extracciones de Starr siguen apagadas." + }, "disableRecursion": { "label": "Recursión", "description": "Extraer archivos encontrados dentro de otros archivos.", diff --git a/frontend/src/lib/i18n/locales/nl.json b/frontend/src/lib/i18n/locales/nl.json index 7dfa7a8b..9f131cca 100644 --- a/frontend/src/lib/i18n/locales/nl.json +++ b/frontend/src/lib/i18n/locales/nl.json @@ -523,8 +523,8 @@ }, "fileMode": { "label": "Bestandsmodus", - "description": "Modus voor uitgepakte bestanden. Uitvoerbits uit het archief blijven behouden.", - "tooltip": "Alleen Unix. Een uitvoerbit uit het archief blijft alleen staan voor eigenaar, groep of anderen als deze modus die klasse al toegang geeft. De umask van het proces geldt nog. Wordt op Windows genegeerd." + "description": "Modus voor uitgepakte bestanden.", + "tooltip": "Alleen Unix. Uitgepakte bestanden krijgen deze modus. De umask van het proces geldt nog. Wordt op Windows genegeerd." }, "dirMode": { "label": "Mapmodus", @@ -797,6 +797,11 @@ "description": ".iso-bestanden als archieven behandelen.", "tooltip": "Uit negeert ISO-images. Zet dit alleen aan als je ze echt wilt uitpakken." }, + "preserve_exec": { + "label": "Uitvoerbits behouden", + "description": "Uitvoerbits uit het archief behouden.", + "tooltip": "Uit krijgen uitgepakte bestanden alleen de bestandsmodus. Aan blijft een uitvoerbit uit het archief staan voor eigenaar, groep of anderen als de bestandsmodus die klasse al toegang geeft. Starr-extracties blijven uit." + }, "disableRecursion": { "label": "Recursie", "description": "Archieven in andere archieven uitpakken.", diff --git a/frontend/src/lib/slug.ts b/frontend/src/lib/slug.ts index 01317452..060d8b23 100644 --- a/frontend/src/lib/slug.ts +++ b/frontend/src/lib/slug.ts @@ -192,6 +192,7 @@ export const FOLDER_ENV_FIELDS: Record = { move_back: 'MOVE_BACK', delete_after: 'DELETE_AFTER', extract_isos: 'EXTRACT_ISOS', + preserve_exec: 'PRESERVE_EXEC', disableRecursion: 'DISABLE_RECURSION', maxNested: 'MAX_NESTED', extrasMaxDepth: 'EXTRAS_MAX_DEPTH', diff --git a/frontend/src/lib/types.ts b/frontend/src/lib/types.ts index 659bf282..5c0a9bbd 100644 --- a/frontend/src/lib/types.ts +++ b/frontend/src/lib/types.ts @@ -294,6 +294,7 @@ export interface FolderConfig { move_back: boolean delete_after: string | null extract_isos: boolean + preserve_exec: boolean disableRecursion: boolean maxNested: number extrasMaxDepth: number diff --git a/frontend/src/pages/settings/FoldersForm.svelte b/frontend/src/pages/settings/FoldersForm.svelte index dfacdfbe..a5543723 100644 --- a/frontend/src/pages/settings/FoldersForm.svelte +++ b/frontend/src/pages/settings/FoldersForm.svelte @@ -80,6 +80,7 @@ move_back: false, delete_after: '', extract_isos: false, + preserve_exec: false, disableRecursion: false, maxNested: 0, extrasMaxDepth: 0, @@ -469,6 +470,18 @@ envVar={envField(envPrefix, slug, 'EXTRACT_ISOS')} /> + + + Folder Config: 1 path: %s%s; delete_after:%v delete_orig:%v delete_files:%v "+ - "log_file:%v move_back:%v isos:%v skip_empty:%v wait_ext:%v max_bytes:%s files:%d ratio:%g "+ + "log_file:%v move_back:%v isos:%v preserve_exec:%v skip_empty:%v wait_ext:%v max_bytes:%s files:%d ratio:%g "+ "nested:%d extras_depth:%d symlinks:%v poll:%v event_buffer:%d", folder.Path, epath, folder.DeleteAfter, folder.DeleteOrig, folder.DeleteFiles, - !folder.DisableLog, folder.MoveBack, folder.ExtractISOs, folder.SkipEmpty, folder.WaitExtensions, + !folder.DisableLog, folder.MoveBack, folder.ExtractISOs, folder.PreserveExec, folder.SkipEmpty, folder.WaitExtensions, logMaxBytes(folder.MaxBytes, "uncapped"), folder.MaxFiles, folder.MaxRatio, folder.MaxNested, folder.ExtrasMaxDepth, folder.AllowSymlinks, folder.Interval, u.Folder.Buffer) } else { @@ -195,10 +195,10 @@ func (u *Unpackerr) logFolders(printf configLine) { } printf(" => Path: %s%s; delete_after:%v delete_orig:%v delete_files:%v log_file:%v "+ - "move_back:%v isos:%v skip_empty:%v wait_ext:%v max_bytes:%s files:%d ratio:%g "+ + "move_back:%v isos:%v preserve_exec:%v skip_empty:%v wait_ext:%v max_bytes:%s files:%d ratio:%g "+ "nested:%d extras_depth:%d symlinks:%v poll:%v", folder.Path, epath, folder.DeleteAfter, folder.DeleteOrig, folder.DeleteFiles, - !folder.DisableLog, folder.MoveBack, folder.ExtractISOs, folder.SkipEmpty, folder.WaitExtensions, + !folder.DisableLog, folder.MoveBack, folder.ExtractISOs, folder.PreserveExec, folder.SkipEmpty, folder.WaitExtensions, logMaxBytes(folder.MaxBytes, "uncapped"), folder.MaxFiles, folder.MaxRatio, folder.MaxNested, folder.ExtrasMaxDepth, folder.AllowSymlinks, folder.Interval) } diff --git a/pkg/unpackerr/folder.go b/pkg/unpackerr/folder.go index be013055..01d7d59b 100644 --- a/pkg/unpackerr/folder.go +++ b/pkg/unpackerr/folder.go @@ -116,6 +116,7 @@ func (u *Unpackerr) extractTrackedItem(name string, folder *Folder, now time.Tim Path: name, ExcludeSuffix: exclude, AllowSymlinks: folder.Config.AllowSymlinks, + PreserveExec: folder.Config.PreserveExec, MaxBytes: folder.Config.ResolvedMaxBytes, MaxFiles: folder.Config.MaxFiles, MaxRatio: folder.Config.MaxRatio, diff --git a/pkg/unpackerr/openapi.json b/pkg/unpackerr/openapi.json index 04196eae..a89b0fe8 100644 --- a/pkg/unpackerr/openapi.json +++ b/pkg/unpackerr/openapi.json @@ -382,6 +382,7 @@ "move_back": {"type": "boolean"}, "delete_after": {"type": "string", "nullable": true, "description": "Go duration; null omits"}, "extract_isos": {"type": "boolean"}, + "preserve_exec": {"type": "boolean", "description": "Keep archive execute bits. Off, files use file_mode only."}, "disableRecursion": {"type": "boolean"}, "maxNested": {"type": "integer"}, "extrasMaxDepth": {"type": "integer"},