@@ -568,12 +568,22 @@ int PoscDir::Opendir(const char *path, XrdOucEnv &env) {
568568}
569569
570570int PoscDir::Readdir (char *buff, int blen) {
571- m_stat_avail = false ;
572571 while (true ) {
573572 auto rc = wrapDF.Readdir (buff, blen);
574573 if (rc) {
574+ if (m_stat_external) {
575+ memset (m_stat_external, ' \0 ' , sizeof (*m_stat_external));
576+ }
575577 return rc;
576578 }
579+ // If the auto-stat protocol is supported, then the Readdir will have
580+ // populated the stat buffer. Copy it over to the user-provided one.
581+ // Note that we have our internal `struct stat` to prevent potential
582+ // bugs where ignored / invisible directory entries are leaked out
583+ // to the caller.
584+ if (m_stat_external) {
585+ memcpy (m_stat_external, &m_stat, sizeof (*m_stat_external));
586+ }
577587 if (*buff == ' \0 ' ) {
578588 return 0 ;
579589 } else if (!strcmp (buff, " ." ) || !strcmp (buff, " .." )) {
@@ -593,27 +603,21 @@ int PoscDir::Readdir(char *buff, int blen) {
593603 " directory" ,
594604 path.string ().c_str ());
595605 }
606+ if (m_stat_external) {
607+ memset (m_stat_external, ' \0 ' , sizeof (*m_stat_external));
608+ }
596609 } else {
597610 return 0 ;
598611 }
599612 }
600613}
601614
602- // Returns the struct stat corresponding to the current
603- // directory entry name .
615+ // Saves the provided pointer to internal memory if the
616+ // wrapped directory supports the "auto stat" protocol .
604617//
605- // If `Readdir` required a stat of the path to determine
606- // if its visible, the cached copy may be served here.
607618int PoscDir::StatRet (struct stat *buff) {
608- if (m_stat_avail) {
609- memcpy (buff, &m_stat, sizeof (m_stat));
610- return 0 ;
611- }
612619 auto rc = wrapDF.StatRet (&m_stat);
613- if (!rc) {
614- m_stat_avail = true ;
615- memcpy (buff, &m_stat, sizeof (m_stat));
616- }
620+ m_stat_external = rc ? nullptr : buff;
617621 return rc;
618622}
619623
0 commit comments