Skip to content

Commit 2334b14

Browse files
committed
Fix POSC plugin symlink creation and validation
Check for existing symlinks and validate they point to the correct in-progress directory. Ensure symlink targets are always absolute paths.
1 parent 3a6ec47 commit 2334b14

File tree

2 files changed

+66
-5
lines changed

2 files changed

+66
-5
lines changed

xrootd/resources/xrootd-origin.cfg

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,9 @@ all.pidpath {{.Origin.RunLocation}}
6161
# enable POSC plugin
6262
ofs.osslib ++ libXrdOssPosc.so
6363
posc.trace {{.Logging.OriginOss}}
64-
# posc.prefix {{.Origin.InProgressLocation}}
64+
# posc.prefix is set to /in-progress relative to oss.localroot
65+
# The actual directory location is configured via Origin.InProgressLocation
66+
# and symlinked to /in-progress under the export path
6567
posc.prefix /in-progress
6668

6769
oss.localroot {{.Xrootd.Mount}}

xrootd/xrootd_config.go

Lines changed: 63 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -315,11 +315,70 @@ func CheckOriginXrootdEnv(exportPath string, server server_structs.XRootDServer,
315315
}
316316
}
317317
// At this point, the in-progress directory is created and owned by the user specified in the config
318-
// We need to symlink the user-specified in-progress directory to the actual in-progress directory
318+
// We need to symlink from the export path (where POSC will look) to the user-specified in-progress directory
319+
inProgressSymlinkPath := filepath.Join(exportPath, "in-progress")
320+
321+
// Check if symlink already exists and remove it if it points to the wrong location
322+
if linkInfo, err := os.Lstat(inProgressSymlinkPath); err == nil {
323+
if linkInfo.Mode()&os.ModeSymlink != 0 {
324+
// It's a symlink - check if it points to the correct location
325+
existingTarget, err := os.Readlink(inProgressSymlinkPath)
326+
if err != nil {
327+
return errors.Wrapf(err, "Failed to read existing in-progress symlink at %v", inProgressSymlinkPath)
328+
}
329+
// Resolve the symlink target to an absolute path
330+
// If the target is relative, resolve it relative to the symlink's directory
331+
var absExistingTarget string
332+
if filepath.IsAbs(existingTarget) {
333+
absExistingTarget = existingTarget
334+
} else {
335+
absExistingTarget = filepath.Join(filepath.Dir(inProgressSymlinkPath), existingTarget)
336+
absExistingTarget = filepath.Clean(absExistingTarget)
337+
}
338+
// Resolve to absolute path (handles any remaining ".." components)
339+
absExistingTarget, err = filepath.Abs(absExistingTarget)
340+
if err != nil {
341+
return errors.Wrapf(err, "Failed to resolve absolute path of existing symlink target %v", existingTarget)
342+
}
343+
absInProgressDir, err := filepath.Abs(inProgressDir)
344+
if err != nil {
345+
return errors.Wrapf(err, "Failed to resolve absolute path of in-progress directory %v", inProgressDir)
346+
}
347+
if absExistingTarget != absInProgressDir {
348+
log.Infof("Removing existing in-progress symlink at %v (points to %v, should point to %v)",
349+
inProgressSymlinkPath, existingTarget, inProgressDir)
350+
if err = os.Remove(inProgressSymlinkPath); err != nil {
351+
return errors.Wrapf(err, "Failed to remove existing in-progress symlink at %v", inProgressSymlinkPath)
352+
}
353+
} else {
354+
// Symlink already points to the correct location, no need to recreate it
355+
log.Debugf("In-progress symlink at %v already points to the correct location %v", inProgressSymlinkPath, inProgressDir)
356+
// Continue with the rest of the function - don't return early
357+
}
358+
} else {
359+
// Path exists but is not a symlink - this is an error
360+
return errors.Errorf("In-progress path %v exists but is not a symlink", inProgressSymlinkPath)
361+
}
362+
} else if !os.IsNotExist(err) {
363+
return errors.Wrapf(err, "Failed to stat in-progress symlink at %v", inProgressSymlinkPath)
364+
}
319365

320-
err = os.Symlink(inProgressDir, filepath.Join(exportPath, "in-progress"))
321-
if err != nil {
322-
return errors.Wrapf(err, "Failed to create in-progress symlink from %v to %v", inProgressDir, filepath.Join(exportPath, "in-progress"))
366+
// Create symlink: the symlink at exportPath/in-progress points to inProgressDir
367+
// This allows POSC (configured with posc.prefix /in-progress) to find the actual directory
368+
// POSC will resolve /in-progress relative to oss.localroot (which is exportPath)
369+
// Only create the symlink if it doesn't already exist or was removed above
370+
if _, err := os.Lstat(inProgressSymlinkPath); os.IsNotExist(err) {
371+
// Ensure we use an absolute path for the symlink target to avoid issues
372+
// if the working directory changes
373+
absInProgressDir, err := filepath.Abs(inProgressDir)
374+
if err != nil {
375+
return errors.Wrapf(err, "Failed to resolve absolute path of in-progress directory %v", inProgressDir)
376+
}
377+
err = os.Symlink(absInProgressDir, inProgressSymlinkPath)
378+
if err != nil {
379+
return errors.Wrapf(err, "Failed to create in-progress symlink from %v to %v", absInProgressDir, inProgressSymlinkPath)
380+
}
381+
log.Debugf("Created in-progress symlink at %v pointing to %v", inProgressSymlinkPath, absInProgressDir)
323382
}
324383
}
325384

0 commit comments

Comments
 (0)