@@ -186,6 +186,16 @@ bool PoscFileSystem::Config(const char *configfn) {
186186
187187int PoscFileSystem::Create (const char *tid, const char *path, mode_t mode,
188188 XrdOucEnv &env, int opts) {
189+ // The open flags are passed in opts >> 8. If O_CREAT or O_TRUNC are set,
190+ // POSC will handle the file creation in Open(), so we should NOT create
191+ // the file here at the final destination. This prevents an empty file
192+ // from appearing in the exported directory during upload.
193+ int open_flags = opts >> 8 ;
194+ if (open_flags & (O_CREAT | O_TRUNC)) {
195+ m_log->Log (LogMask::Debug, " POSC" ,
196+ " Skipping Create for POSC-handled file:" , path);
197+ return 0 ;
198+ }
189199 return VerifyPath (path, &XrdOss::Create, tid, path, mode, env, opts);
190200}
191201
@@ -709,6 +719,7 @@ int PoscFile::Close(long long *retsz) {
709719 auto close_rv = wrapDF.Close (retsz);
710720 if (close_rv) {
711721 m_oss.Unlink (m_posc_filename.c_str (), 0 , m_posc_env.get ());
722+ m_posc_filename.clear ();
712723 return close_rv;
713724 }
714725
@@ -719,9 +730,36 @@ int PoscFile::Close(long long *retsz) {
719730 m_posc_filename.c_str (), strerror (-rv));
720731
721732 m_oss.Unlink (m_posc_filename.c_str (), 0 , m_posc_env.get ());
733+ m_posc_filename.clear ();
722734 return -EIO;
723735 }
724736
737+ // Expected file size is advisory; if it is present, verify it matches
738+ // before persisting Otherwise, we don't know the expected file size, so we
739+ // don't verify it and just persist the file.
740+ if (m_expected_size > 0 ) {
741+ struct stat sb;
742+ rv = m_oss.Stat (m_posc_filename.c_str (), &sb, 0 , m_posc_env.get ());
743+ if (rv) {
744+ m_log.Log (LogMask::Error, " POSC" , " Failed to stat POSC file" ,
745+ m_posc_filename.c_str (), strerror (-rv));
746+ m_oss.Unlink (m_posc_filename.c_str (), 0 , m_posc_env.get ());
747+ m_posc_filename.clear ();
748+ return -EIO;
749+ }
750+ if (sb.st_size != m_expected_size) {
751+ std::stringstream ss;
752+ m_log.Log (LogMask::Error, " POSC" , ss.str ().c_str (),
753+ m_posc_filename.c_str ());
754+ m_oss.Unlink (m_posc_filename.c_str (), 0 , m_posc_env.get ());
755+ m_posc_filename.clear ();
756+ return -EIO;
757+ }
758+ }
759+
760+ // At this point, we either don't know the expected file size, or the file
761+ // size matches the expected size. So we can persist the file.
762+
725763 rv = m_oss.Rename (m_posc_filename.c_str (), m_orig_filename.c_str (),
726764 m_posc_env.get (), m_posc_env.get ());
727765 if (rv) {
@@ -731,9 +769,10 @@ int PoscFile::Close(long long *retsz) {
731769 m_log.Log (LogMask::Error, " POSC" , ss.str ().c_str ());
732770
733771 m_oss.Unlink (m_posc_filename.c_str (), 0 , m_posc_env.get ());
734-
772+ m_posc_filename. clear ();
735773 return -EIO;
736774 }
775+ m_posc_filename.clear ();
737776 return 0 ;
738777}
739778
@@ -744,7 +783,7 @@ int PoscFile::Open(const char *path, int Oflag, mode_t Mode, XrdOucEnv &env) {
744783 return -ENOENT;
745784 }
746785
747- if ((Oflag & O_CREAT) == 0 ) {
786+ if ((Oflag & ( O_CREAT | O_TRUNC) ) == 0 ) {
748787 return wrapDF.Open (path, Oflag, Mode, env);
749788 }
750789
@@ -776,14 +815,27 @@ int PoscFile::Open(const char *path, int Oflag, mode_t Mode, XrdOucEnv &env) {
776815 auto envbuff = env.Env (envlen);
777816 m_posc_env.reset (new XrdOucEnv (envbuff, envlen, m_posc_entity.get ()));
778817 m_posc_mode = Mode;
818+
819+ // Extract expected file size from oss.asize if available
820+ char *asize_char = env.Get (" oss.asize" );
821+ if (asize_char) {
822+ char *endptr;
823+ long long asize = strtoll (asize_char, &endptr, 10 );
824+ if (endptr != asize_char && *endptr == ' \0 ' && asize >= 0 ) {
825+ m_expected_size = static_cast <off_t >(asize);
826+ m_log.Log (LogMask::Debug, " POSC" , " Expected file size:" ,
827+ std::to_string (m_expected_size).c_str ());
828+ }
829+ }
830+
779831 m_posc_mtime.store (
780832 std::chrono::system_clock::now ().time_since_epoch ().count (),
781833 std::memory_order_relaxed);
782834 for (int idx = 0 ; idx < 10 ; ++idx) {
783835 m_posc_filename = m_posc_fs.GeneratePoscFile (path, env);
784836
785- auto rv =
786- wrapDF. Open (m_posc_filename. c_str (), Oflag | O_EXCL, 0600 , env);
837+ auto rv = wrapDF. Open (m_posc_filename. c_str (), Oflag | O_EXCL | O_CREAT,
838+ 0600 , env);
787839 if (rv >= 0 ) {
788840 m_log.Log (LogMask::Debug, " POSC" , " Opened POSC file" ,
789841 m_posc_filename.c_str ());
@@ -805,10 +857,11 @@ int PoscFile::Open(const char *path, int Oflag, mode_t Mode, XrdOucEnv &env) {
805857 m_log.Log (LogMask::Debug, " POSC" ,
806858 " POSC sub-directory is needed for file creation:" ,
807859 posc_dir.c_str ());
808- if (m_oss.Mkdir (posc_dir.c_str (), 0700 , 1 , &env) != 0 ) {
860+ auto mkdir_rv = m_oss.Mkdir (posc_dir.c_str (), 0700 , 1 , &env);
861+ if (mkdir_rv != 0 ) {
809862 m_log.Log (LogMask::Error, " POSC" ,
810863 " Failed to create POSC sub-directory" ,
811- posc_dir.c_str (), strerror (errno ));
864+ posc_dir.c_str (), strerror (-mkdir_rv ));
812865 return -EIO;
813866 }
814867 } else if (rv == -EINTR) {
0 commit comments