···331331 // if not link, return self
332332 // see https://github.com/PowerShell/PowerShell/issues/25724
333333 public FileSystemInfo? ReadLink() {
334334- if (!fsi.Attributes.HasFlag(FileAttributes.ReparsePoint)) {
334334+ if (!fsi.Attributes.HasFlag(FileAttributes.ReparsePoint))
335335 return null;
336336- }
337336338338- if (OperatingSystem.IsWindows()) {
337337+ if (OperatingSystem.IsWindows())
339338 return fsi.ResolveLinkTarget(true);
340340- }
341339342340 Process rp = new Process {
343341 StartInfo = new ProcessStartInfo("realpath", ["-m", fsi.FullName]) {
···349347 rp.Start();
350348 var real = rp.StandardOutput.ReadLine();
351349 rp.WaitForExit();
352352-353353- if (Directory.Exists(real)) {
350350+351351+ if (Directory.Exists(real))
354352 return new DirectoryInfo(real);
355355- }
356356-357357- // the file at real might not actually exist, but we want to return it anyways
358358- return new FileInfo(real ?? "");
353353+354354+ if (File.Exists(real))
355355+ return new FileInfo(real);
356356+357357+ throw new FileNotFoundException($"Link target for {fsi.FullName} -> {fsi.LinkTarget} not found.");
359358 }
360359361361- // TODO: uhh this might loop if the target doesnt exist
362360 public FileSystemInfo UnravelLink() {
363363- FileSystemInfo floor = fsi ?? throw new ArgumentNullException(nameof(fsi));
361361+ FileSystemInfo here = fsi ?? throw new ArgumentNullException(nameof(fsi));
362362+ FileSystemInfo? next;
363363+364364+ while (true) {
365365+ // let the exception propagate
366366+ next = here.ReadLink();
367367+368368+ if (next == null)
369369+ return here;
364370365365- while (true) {
366366- if (floor!.ReadLink() != null) {
367367- floor = floor!.ReadLink()!;
368368- } else {
369369- return floor;
370370- }
371371+ here = next;
371372 }
372372-373373 }
374374 }
375375