mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-14 02:38:20 +02:00
Un compte non administrateur ne peut pas renommer C:\ProgramData\jean : le droit manquant porte sur C:\ProgramData. Ces postes gardaient donc l'ancien nom indefiniment. Les 0.7.1 et 0.7.2 avaient traite le bruit, pas le fond. L'installation relance desormais AJEAN en administrateur le temps de la SEULE migration (sous-commande interne, absente de l'aide), puis rend la main. Un refus de la fenetre UAC est une reponse valable : on continue sur l'ancien chemin, sans rien casser. Deux tentatives de discrimination ont echoue avant celle-ci, et le detail compte pour qui relira ce code : - Le code d'erreur ne distingue rien. Windows renvoie ERROR_ACCESS_DENIED aussi bien pour un manque de droits que pour un dossier verrouille par un programme en cours. Un test le prouve, il avait ete ecrit en croyant l'inverse. - Sonder l'ecriture dans le dossier parent ne distingue rien non plus : ProgramData autorise la creation de fichiers aux utilisateurs standards, c'est la suppression/renommage d'une entree existante qui est refusee. C'est donc le LIEU D'APPEL qui selectionne, et lui est fiable : on n'eleve que depuis `install` et depuis l'installeur de mise a jour, tous deux apres l'arret des instances. Le cas « verrouille » y est deja ecarte. Note pour les tests : ne JAMAIS appeler elevateForHomeMigration() sous `go test`. os.Executable() y designe le binaire de test, que l'elevation relance — donc toute la suite, en boucle. Constate.
80 lines
3.2 KiB
Go
80 lines
3.2 KiB
Go
//go:build windows
|
|
|
|
package ajean
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"strings"
|
|
)
|
|
|
|
// Élévation ponctuelle pour terminer la migration du dossier de données.
|
|
//
|
|
// Renommer %ProgramData%\jean exige d'écrire dans %ProgramData%, ce qu'un compte
|
|
// standard ne peut pas faire. Sans élévation, ces postes gardent l'ancien nom
|
|
// pour toujours — ce qui est sans conséquence, mais laisse le renommage à
|
|
// moitié fait.
|
|
//
|
|
// La fenêtre UAC n'apparaît QUE si elle sert à quelque chose :
|
|
//
|
|
// - migration déjà faite, inutile, ou chemin imposé par l'utilisateur → rien ;
|
|
// - migration en attente, dans un parcours d'installation → on demande.
|
|
//
|
|
// On ne cherche PAS à deviner la cause depuis le code d'erreur : Windows renvoie
|
|
// ERROR_ACCESS_DENIED aussi bien pour un manque de droits que pour un dossier
|
|
// verrouillé par un programme en cours. Impossible de les séparer — vérifié.
|
|
//
|
|
// C'est donc le LIEU D'APPEL qui fait la sélection, et lui est fiable : on
|
|
// n'élève que depuis `install` et depuis l'installeur de mise à jour, tous deux
|
|
// après l'arrêt des instances en cours. Le cas « verrouillé » y est déjà écarté ;
|
|
// ce qui reste est un problème de droits, que l'élévation résout.
|
|
|
|
// migrateHomeArg est la sous-commande interne exécutée par le process élevé.
|
|
// Absente de l'aide : ce n'est pas une commande destinée aux utilisateurs, mais
|
|
// le travail précis qu'on délègue à un process ayant les droits.
|
|
const migrateHomeArg = "migrate-home-elevated"
|
|
|
|
// cmdMigrateHomeElevated est le point d'entrée du process élevé : il migre, dit
|
|
// ce qu'il a fait, et rend la main. Rien d'autre — moins il en fait sous des
|
|
// droits administrateur, mieux c'est.
|
|
func cmdMigrateHomeElevated() error {
|
|
if retryHomeMigration() {
|
|
fmt.Printf("%s dossier de données migré vers %s\n", green("✓"), AjeanHome())
|
|
return nil
|
|
}
|
|
if migrationDeferred != "" {
|
|
return fmt.Errorf("migration toujours impossible : %s", migrationDeferred)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// elevateForHomeMigration relance AJEAN en administrateur le temps de la seule
|
|
// migration, puis revérifie. Renvoie true si le dossier a effectivement changé.
|
|
//
|
|
// Silencieux et sans effet quand l'élévation ne servirait à rien, y compris si
|
|
// l'utilisateur refuse la fenêtre UAC : son refus est une réponse valable, la
|
|
// machine continue de fonctionner sur l'ancien chemin.
|
|
func elevateForHomeMigration() bool {
|
|
if migrationDeferred == "" {
|
|
return false
|
|
}
|
|
exe, err := os.Executable()
|
|
if err != nil {
|
|
return false
|
|
}
|
|
// Start-Process -Verb RunAs déclenche l'invite UAC ; -Wait pour que la suite
|
|
// de l'installation reparte sur le bon dossier, pas sur l'ancien.
|
|
ps := fmt.Sprintf(
|
|
`try { Start-Process -FilePath %s -ArgumentList '%s' -Verb RunAs -Wait -WindowStyle Hidden; 'ok' } catch { 'refus' }`,
|
|
psQuote(exe), migrateHomeArg)
|
|
out, err := hideCmd(exec.Command("powershell", "-NoProfile", "-Command", ps)).CombinedOutput()
|
|
if err != nil || !strings.Contains(string(out), "ok") {
|
|
return false // refus de l'utilisateur, ou élévation indisponible
|
|
}
|
|
// Le process élevé a fait le travail dans SON espace mémoire : on relit le
|
|
// disque pour savoir ce qu'il en est réellement ici.
|
|
migrationDeferred = ""
|
|
return retryHomeMigration()
|
|
}
|