XRootD
XrdClFS.cc
Go to the documentation of this file.
1 //------------------------------------------------------------------------------
2 // Copyright (c) 2011-2014 by European Organization for Nuclear Research (CERN)
3 // Author: Lukasz Janyst <ljanyst@cern.ch>
4 //------------------------------------------------------------------------------
5 // This file is part of the XRootD software suite.
6 //
7 // XRootD is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Lesser General Public License as published by
9 // the Free Software Foundation, either version 3 of the License, or
10 // (at your option) any later version.
11 //
12 // XRootD is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
16 //
17 // You should have received a copy of the GNU Lesser General Public License
18 // along with XRootD. If not, see <http://www.gnu.org/licenses/>.
19 //
20 // In applying this licence, CERN does not waive the privileges and immunities
21 // granted to it by virtue of its status as an Intergovernmental Organization
22 // or submit itself to any jurisdiction.
23 //------------------------------------------------------------------------------
24 
25 #include "XProtocol/XProtocol.hh"
26 #include "XrdCl/XrdClConstants.hh"
28 #include "XrdCl/XrdClDefaultEnv.hh"
29 #include "XrdCl/XrdClFSExecutor.hh"
30 #include "XrdCl/XrdClFile.hh"
31 #include "XrdCl/XrdClFileSystem.hh"
34 #include "XrdCl/XrdClLog.hh"
36 #include "XrdCl/XrdClStatus.hh"
37 #include "XrdCl/XrdClURL.hh"
38 #include "XrdCl/XrdClUtils.hh"
41 #include "XrdSys/XrdSysE2T.hh"
42 
43 #include <algorithm>
44 #include <cctype>
45 #include <getopt.h>
46 #include <iterator>
47 #include <cmath>
48 #include <cstdio>
49 #include <cstdlib>
50 #include <iomanip>
51 #include <iostream>
52 
53 #ifdef HAVE_READLINE
54 #include <readline/history.h>
55 #include <readline/readline.h>
56 #endif
57 
58 using namespace XrdCl;
59 
60 namespace
61 {
62  enum URLCommandResult
63  {
64  NotURLCommand,
65  ValidURLCommand,
66  InvalidURLCommand
67  };
68 
69  bool SupportsFullURLs( const std::string &command )
70  {
71  static const char *commands[] = {
72  "cache", "cat", "chmod", "locate", "ls", "mkdir", "mv",
73  "prepare", "rm", "rmdir", "spaceinfo", "stat", "statvfs",
74  "tail", "truncate", "xattr"
75  };
76 
77  return std::find( std::begin( commands ), std::end( commands ), command )
78  != std::end( commands );
79  }
80 
81  // XrdCl::URL also accepts bare hosts and local paths. Keep this small check
82  // to distinguish explicit URL operands from those shorthand forms and from
83  // values such as "name=https://example.org".
84  bool HasExplicitURLScheme( const std::string &argument )
85  {
86  std::string::size_type separator = argument.find( "://" );
87  if( separator == std::string::npos || separator == 0
88  || !std::isalpha( static_cast<unsigned char>( argument[0] ) ) )
89  return false;
90 
91  for( std::string::size_type i = 1; i < separator; ++i )
92  {
93  unsigned char character = static_cast<unsigned char>( argument[i] );
94  if( !std::isalnum( character ) && character != '+'
95  && character != '-' && character != '.' )
96  return false;
97  }
98 
99  return true;
100  }
101 
102  URLCommandResult ParseURLCommand( FSExecutor::CommandParams &arguments,
103  URL &endpoint, std::string &error )
104  {
105  if( arguments.empty() )
106  return NotURLCommand;
107 
108  if( arguments[0] == "query" )
109  {
110  for( std::size_t i = 1; i < arguments.size(); ++i )
111  {
112  if( HasExplicitURLScheme( arguments[i] ) )
113  {
114  error = "command-first full URLs are not supported for 'query'";
115  return InvalidURLCommand;
116  }
117  }
118  return NotURLCommand;
119  }
120 
121  if( !SupportsFullURLs( arguments[0] ) )
122  return NotURLCommand;
123 
124  bool foundURL = false;
125  for( std::size_t i = 1; i < arguments.size(); ++i )
126  {
127  if( !HasExplicitURLScheme( arguments[i] ) )
128  continue;
129 
130  URL operand( arguments[i] );
131  if( !operand.IsValid() || operand.GetProtocol() == "file"
132  || operand.GetProtocol() == "stdio" )
133  {
134  error = "invalid remote URL operand";
135  return InvalidURLCommand;
136  }
137 
138  if( !foundURL )
139  {
140  endpoint = operand;
141  endpoint.SetPath( "" );
142  endpoint.SetParams( URL::ParamsMap() );
143  foundURL = true;
144  }
145  else if( endpoint.GetProtocol() != operand.GetProtocol()
146  || endpoint.GetHostId() != operand.GetHostId() )
147  {
148  error = "all URL operands must use the same endpoint";
149  return InvalidURLCommand;
150  }
151 
152  arguments[i] = operand.GetPathWithParams();
153  if( arguments[i].empty() || arguments[i][0] != '/' )
154  arguments[i].insert( arguments[i].begin(), '/' );
155  }
156 
157  return foundURL ? ValidURLCommand : NotURLCommand;
158  }
159 }
160 
161 //------------------------------------------------------------------------------
162 // Build a path
163 //------------------------------------------------------------------------------
164 XRootDStatus BuildPath( std::string &newPath, Env *env,
165  const std::string &path,
166  const char *op = nullptr )
167 {
168  Log *log = DefaultEnv::GetLog();
169 
170  if( path.empty() )
171  {
172  const std::string msg = "A path is required.";
173  log->Error( AppMsg, "%s", msg.c_str() );
174  return XRootDStatus( stError, errInvalidArgs, 0, msg );
175  }
176 
177  int noCwd = 0;
178  env->GetInt( "NoCWD", noCwd );
179 
180  if( path[0] == '/' )
181  {
182  newPath = path;
183  return XRootDStatus();
184  }
185  else if( noCwd )
186  {
187  std::string msg;
188  if( op )
189  msg = std::string( op ) + " relative path '" + path + "' is disallowed.";
190  else
191  msg = "Relative path '" + path + "' is disallowed.";
192  log->Error( AppMsg, "%s", msg.c_str() );
193  return XRootDStatus( stError, errInvalidArgs, 0, msg );
194  }
195 
196  std::string cwd = "/";
197  env->GetString( "CWD", cwd );
198  newPath = cwd;
199  newPath += "/";
200  newPath += path;
201 
202  //----------------------------------------------------------------------------
203  // Collapse the dots
204  //----------------------------------------------------------------------------
205  std::list<std::string> pathComponents;
206  std::list<std::string>::iterator it;
207  XrdCl::Utils::splitString( pathComponents, newPath, "/" );
208  newPath = "/";
209  for( it = pathComponents.begin(); it != pathComponents.end(); )
210  {
211  if( *it == "." )
212  {
213  it = pathComponents.erase( it );
214  continue;
215  }
216 
217  if( *it == ".." )
218  {
219  if( it == pathComponents.begin() )
220  {
221  const std::string msg = "Path '" + path + "' escapes above root.";
222  log->Error( AppMsg, "%s", msg.c_str() );
223  return XRootDStatus( stError, errInvalidArgs, 0, msg );
224  }
225  std::list<std::string>::iterator it1 = it;
226  --it1;
227  it = pathComponents.erase( it1 );
228  it = pathComponents.erase( it );
229  continue;
230  }
231  ++it;
232  }
233 
234  newPath = "/";
235  for( it = pathComponents.begin(); it != pathComponents.end(); ++it )
236  {
237  newPath += *it;
238  newPath += "/";
239  }
240  if( newPath.length() > 1 )
241  newPath.erase( newPath.length()-1, 1 );
242 
243  return XRootDStatus();
244 }
245 
246 //------------------------------------------------------------------------------
247 // Convert mode string to uint16_t
248 //------------------------------------------------------------------------------
249 XRootDStatus ConvertMode( Access::Mode &mode, const std::string &modeStr )
250 {
251  if( modeStr.length() != 9 )
253 
254  mode = Access::None;
255  for( int i = 0; i < 3; ++i )
256  {
257  if( modeStr[i] == 'r' )
258  mode |= Access::UR;
259  else if( modeStr[i] == 'w' )
260  mode |= Access::UW;
261  else if( modeStr[i] == 'x' )
262  mode |= Access::UX;
263  else if( modeStr[i] != '-' )
265  }
266  for( int i = 3; i < 6; ++i )
267  {
268  if( modeStr[i] == 'r' )
269  mode |= Access::GR;
270  else if( modeStr[i] == 'w' )
271  mode |= Access::GW;
272  else if( modeStr[i] == 'x' )
273  mode |= Access::GX;
274  else if( modeStr[i] != '-' )
276  }
277  for( int i = 6; i < 9; ++i )
278  {
279  if( modeStr[i] == 'r' )
280  mode |= Access::OR;
281  else if( modeStr[i] == 'w' )
282  mode |= Access::OW;
283  else if( modeStr[i] == 'x' )
284  mode |= Access::OX;
285  else if( modeStr[i] != '-' )
287  }
288  return XRootDStatus();
289 }
290 
291 //------------------------------------------------------------------------------
292 // Perform a cache operation
293 //------------------------------------------------------------------------------
295  Env *env,
296  const FSExecutor::CommandParams &args )
297 {
298  //----------------------------------------------------------------------------
299  // Check up the args
300  //----------------------------------------------------------------------------
301  Log *log = DefaultEnv::GetLog();
302  uint32_t argc = args.size();
303 
304  if( argc != 3 )
305  {
306  log->Error( AppMsg, "Wrong number of arguments." );
307  return XRootDStatus( stError, errInvalidArgs, 0,
308  "Wrong number of arguments." );
309  }
310 
311  if( args[1] != "evict" && args[1] != "fevict")
312  {
313  log->Error( AppMsg, "Invalid cache operation." );
314  return XRootDStatus( stError, errInvalidArgs, 0, "Invalid cache operation." );
315  }
316 
317  std::string fullPath;
318  XRootDStatus pathSt = BuildPath( fullPath, env, args[2], "Caching" );
319  if( !pathSt.IsOK() )
320  return pathSt;
321 
322  //----------------------------------------------------------------------------
323  // Create the command
324  //----------------------------------------------------------------------------
325  std::string cmd = args[1];
326  cmd.append(" ");
327  cmd.append(fullPath);
328 
329  //----------------------------------------------------------------------------
330  // Run the operation
331  //----------------------------------------------------------------------------
332  Buffer *response = 0;
333  XRootDStatus st = fs->SendCache( cmd, response );
334  if( !st.IsOK() )
335  {
336  log->Error( AppMsg, "Unable set cache %s: %s",
337  fullPath.c_str(),
338  st.ToStr().c_str() );
339  return st;
340  }
341 
342  if( response )
343  {
344  std::cout << response->ToString() << '\n';
345  }
346 
347  delete response;
348 
349  return XRootDStatus();
350 }
351 //------------------------------------------------------------------------------
352 // Change current working directory
353 //------------------------------------------------------------------------------
355  Env *env,
356  const FSExecutor::CommandParams &args )
357 {
358  //----------------------------------------------------------------------------
359  // Check up the args
360  //----------------------------------------------------------------------------
361  Log *log = DefaultEnv::GetLog();
362  if( args.size() != 2 )
363  {
364  log->Error( AppMsg, "Invalid arguments. Expected a path." );
366  }
367 
368  //----------------------------------------------------------------------------
369  // cd excludes NoCWD
370  //----------------------------------------------------------------------------
371  env->PutInt( "NoCWD", 0 );
372 
373  std::string newPath;
374  XRootDStatus pathSt = BuildPath( newPath, env, args[1], "Changing" );
375  if( !pathSt.IsOK() )
376  return pathSt;
377 
378  //----------------------------------------------------------------------------
379  // Check if the path exist and is not a directory
380  //----------------------------------------------------------------------------
381  StatInfo *info;
382  XRootDStatus st = fs->Stat( newPath, info );
383  if( !st.IsOK() )
384  {
385  log->Error( AppMsg, "Unable to stat the path: %s", st.ToStr().c_str() );
386  return st;
387  }
388 
389  if( !info->TestFlags( StatInfo::IsDir ) )
390  {
391  log->Error( AppMsg, "%s is not a directory.", newPath.c_str() );
393  }
394 
395  env->PutString( "CWD", newPath );
396  delete info;
397  return XRootDStatus();
398 }
399 
400 //------------------------------------------------------------------------------
401 // Helper function to calculate number of digits in a number
402 //------------------------------------------------------------------------------
403 uint32_t nbDigits( uint64_t nb )
404 {
405  if( nb == 0 ) return 1;
406  return uint32_t( log10( double(nb) ) + 1);
407 }
408 
409 std::string getSizeStr(uint64_t size, bool human, uint64_t base) {
410  std::ostringstream oss;
411  if (!human) {
412  oss << size;
413  } else {
414  oss << XrdOucUtils::genHumanSize(size,base);
415  }
416  return oss.str();
417 }
418 
419 void PrintDirListStatInfo( StatInfo *info, bool hascks = false, uint32_t ownerwidth = 0, uint32_t groupwidth = 0, uint32_t sizewidth = 0, bool human = false, uint64_t base = 1000 )
420 {
421  if( info->ExtendedFormat() )
422  {
423  if( info->TestFlags( StatInfo::IsDir ) )
424  std::cout << "d";
425  else
426  std::cout << "-";
427  std::cout << info->GetModeAsOctString();
428 
429  std::cout << " " << std::setw( ownerwidth ) << info->GetOwner();
430  std::cout << " " << std::setw( groupwidth ) << info->GetGroup();
431  std::cout << " " << std::setw( sizewidth ) << getSizeStr(info->GetSize(),human, base);
432  if( hascks && info->HasChecksum() )
433  std::cout << " " << std::setw( sizewidth ) << info->GetChecksum();
434  std::cout << " " << info->GetModTimeAsString() << " ";
435  }
436  else
437  {
438  if( info->TestFlags( StatInfo::IsDir ) )
439  std::cout << "d";
440  else
441  std::cout << "-";
442 
443  if( info->TestFlags( StatInfo::IsReadable ) )
444  std::cout << "r";
445  else
446  std::cout << "-";
447 
448  if( info->TestFlags( StatInfo::IsWritable ) )
449  std::cout << "w";
450  else
451  std::cout << "-";
452 
453  if( info->TestFlags( StatInfo::XBitSet ) )
454  std::cout << "x";
455  else
456  std::cout << "-";
457 
458  std::cout << " " << info->GetModTimeAsString();
459 
460  uint64_t size = info->GetSize();
461  std::string displaySize = getSizeStr(size,human,base);
462  int width = displaySize.size() + 2;
463  if (width < 12) {
464  width = 12;
465  }
466  std::cout << std::setw( width ) << displaySize << " ";
467  }
468 }
469 
470 //------------------------------------------------------------------------------
471 // List a directory
472 //------------------------------------------------------------------------------
474  Env *env,
475  const FSExecutor::CommandParams &args )
476 {
477  //----------------------------------------------------------------------------
478  // Check up the args
479  //----------------------------------------------------------------------------
480  Log *log = DefaultEnv::GetLog();
481  uint32_t argc = args.size();
482  bool stats = false;
483  bool showUrls = false;
484  bool hascks = false;
485  bool human = false;
486  uint64_t base = 1024;
487  std::string path;
489 
490  if( argc > 6 )
491  {
492  log->Error( AppMsg, "Too many arguments." );
494  }
495 
496  for( uint32_t i = 1; i < args.size(); ++i )
497  {
498  if( args[i] == "-l" )
499  {
500  stats = true;
501  flags |= DirListFlags::Stat;
502  }
503  else if( args[i] == "-u" )
504  showUrls = true;
505  else if( args[i] == "-R" )
506  {
507  flags |= DirListFlags::Recursive;
508  }
509  else if( args[i] == "-D" )
510  {
511  // show duplicates
512  flags &= ~DirListFlags::Merge;
513  }
514  else if( args[i] == "-Z" )
515  {
516  // check if file is a ZIP archive if yes list content
517  flags |= DirListFlags::Zip;
518  }
519  else if( args[i] == "-C" )
520  {
521  // query checksum for each entry in the directory
522  hascks = true;
523  stats = true;
524  flags |= DirListFlags::Cksm;
525  }
526  else if ( args [i] == "-h" )
527  {
528  human = true;
529  }
530  else
531  path = args[i];
532  }
533 
534  if( showUrls )
535  // we don't merge the duplicate entries
536  // in case we print the full URL
537  flags &= ~DirListFlags::Merge;
538 
539  std::string newPath = "/";
540  if( path.empty() )
541  env->GetString( "CWD", newPath );
542  else
543  {
544  XRootDStatus pathSt = BuildPath( newPath, env, path, "Listing" );
545  if( !pathSt.IsOK() )
546  return pathSt;
547  }
548 
549  //----------------------------------------------------------------------------
550  // Stat the entry so we know if it is a file or a directory
551  //----------------------------------------------------------------------------
552  log->Debug( AppMsg, "Attempting to stat: %s", newPath.c_str() );
553 
554  StatInfo *info = 0;
555  XRootDStatus st = fs->Stat( newPath, info );
556  std::unique_ptr<StatInfo> ptr( info );
557  if( !st.IsOK() )
558  {
559  log->Error( AppMsg, "Unable to stat the path: %s", st.ToStr().c_str() );
560  return st;
561  }
562 
563  if( !info->TestFlags( StatInfo::IsDir ) &&
564  !( flags & DirListFlags::Zip ) )
565  {
566  if( stats )
567  PrintDirListStatInfo( info, false, 0, 0, 0, human, base );
568 
569  if( showUrls )
570  {
571  std::string url;
572  fs->GetProperty( "LastURL", url );
573  std::cout << url;
574  }
575  std::cout << newPath << std::endl;
576  return XRootDStatus();
577  }
578 
579 
580  //----------------------------------------------------------------------------
581  // Ask for the list
582  //----------------------------------------------------------------------------
583  log->Debug( AppMsg, "Attempting to list: %s", newPath.c_str() );
584 
585  DirectoryList *list;
586  st = fs->DirList( newPath, flags, list );
587  if( !st.IsOK() )
588  {
589  log->Error( AppMsg, "Unable to list the path: %s", st.ToStr().c_str() );
590  return st;
591  }
592 
593  if( st.code == suPartial )
594  {
595  std::cerr << "[!] Some of the requests failed. The result may be ";
596  std::cerr << "incomplete." << std::endl;
597  }
598 
599  uint32_t ownerwidth = 0, groupwidth = 0, sizewidth = 0, ckswidth = 0;
601  for( it = list->Begin(); it != list->End() && stats; ++it )
602  {
603  StatInfo *info = (*it)->GetStatInfo();
604 
605  std::string size = getSizeStr(info->GetSize(),human,base);
606  uint32_t sizeWidthComp;
607  if (human) {
608  sizeWidthComp = size.size();
609  } else {
610  sizeWidthComp = nbDigits( info->GetSize());
611  }
612 
613  if( ownerwidth < info->GetOwner().size() )
614  ownerwidth = info->GetOwner().size();
615  if( groupwidth < info->GetGroup().size() )
616  groupwidth = info->GetGroup().size();
617  if( sizewidth < sizeWidthComp )
618  sizewidth = sizeWidthComp;
619  if( ckswidth < info->GetChecksum().size() )
620  ckswidth = info->GetChecksum().size();
621  }
622 
623  //----------------------------------------------------------------------------
624  // Print the results
625  //----------------------------------------------------------------------------
626  for( it = list->Begin(); it != list->End(); ++it )
627  {
628  if( stats )
629  {
630  StatInfo *info = (*it)->GetStatInfo();
631  if( !info )
632  std::cout << "---- 0000-00-00 00:00:00 ? ";
633  else
634  PrintDirListStatInfo( info, hascks, ownerwidth, groupwidth, sizewidth, human, base );
635  }
636  if( showUrls )
637  std::cout << "root://" << (*it)->GetHostAddress() << "/";
638  std::cout << list->GetParentName() << (*it)->GetName() << std::endl;
639  }
640  delete list;
641  return XRootDStatus();
642 }
643 
644 //------------------------------------------------------------------------------
645 // Create a directory
646 //------------------------------------------------------------------------------
648  Env *env,
649  const FSExecutor::CommandParams &args )
650 {
651  //----------------------------------------------------------------------------
652  // Check up the args
653  //----------------------------------------------------------------------------
654  Log *log = DefaultEnv::GetLog();
655  uint32_t argc = args.size();
656 
657  if( argc < 2 || argc > 4 )
658  {
659  log->Error( AppMsg, "Too few arguments." );
661  }
662 
664  Access::Mode mode = Access::None;
665  std::string modeStr = "rwxr-x---";
666  std::string path = "";
667 
668  for( uint32_t i = 1; i < args.size(); ++i )
669  {
670  if( args[i] == "-p" )
671  flags |= MkDirFlags::MakePath;
672  else if( !args[i].compare( 0, 2, "-m" ) )
673  modeStr = args[i].substr( 2, 9 );
674  else
675  path = args[i];
676  }
677 
678  XRootDStatus st = ConvertMode( mode, modeStr );
679  if( !st.IsOK() )
680  {
681  log->Error( AppMsg, "Invalid mode string." );
682  return st;
683  }
684 
685  std::string newPath;
686  XRootDStatus pathSt = BuildPath( newPath, env, path, "Creating" );
687  if( !pathSt.IsOK() )
688  return pathSt;
689 
690  //----------------------------------------------------------------------------
691  // Run the query
692  //----------------------------------------------------------------------------
693  st = fs->MkDir( newPath, flags, mode );
694  if( !st.IsOK() )
695  {
696  log->Error( AppMsg, "Unable create directory %s: %s",
697  newPath.c_str(),
698  st.ToStr().c_str() );
699  return st;
700  }
701 
702  return XRootDStatus();
703 }
704 
705 //------------------------------------------------------------------------------
706 // Remove a directory
707 //------------------------------------------------------------------------------
709  Env *env,
710  const FSExecutor::CommandParams &args )
711 {
712  //----------------------------------------------------------------------------
713  // Check up the args
714  //----------------------------------------------------------------------------
715  Log *log = DefaultEnv::GetLog();
716  uint32_t argc = args.size();
717 
718  if( argc != 2 )
719  {
720  log->Error( AppMsg, "Wrong number of arguments." );
722  }
723 
724  std::string fullPath;
725  XRootDStatus pathSt = BuildPath( fullPath, env, args[1], "Removing" );
726  if( !pathSt.IsOK() )
727  return pathSt;
728 
729  //----------------------------------------------------------------------------
730  // Run the query
731  //----------------------------------------------------------------------------
732  XRootDStatus st = query->RmDir( fullPath );
733  if( !st.IsOK() )
734  {
735  log->Error( AppMsg, "Unable remove directory %s: %s",
736  fullPath.c_str(),
737  st.ToStr().c_str() );
738  return st;
739  }
740 
741  return XRootDStatus();
742 }
743 
744 //------------------------------------------------------------------------------
745 // Move a file or directory
746 //------------------------------------------------------------------------------
748  Env *env,
749  const FSExecutor::CommandParams &args )
750 {
751  //----------------------------------------------------------------------------
752  // Check up the args
753  //----------------------------------------------------------------------------
754  Log *log = DefaultEnv::GetLog();
755  uint32_t argc = args.size();
756 
757  if( argc != 3 )
758  {
759  log->Error( AppMsg, "Wrong number of arguments." );
761  }
762 
763  std::string fullPath1;
764  XRootDStatus pathSt = BuildPath( fullPath1, env, args[1], "Renaming" );
765  if( !pathSt.IsOK() )
766  return pathSt;
767 
768  std::string fullPath2;
769  pathSt = BuildPath( fullPath2, env, args[2], "Renaming to" );
770  if( !pathSt.IsOK() )
771  return pathSt;
772 
773  if( is_subdirectory(fullPath1, fullPath2) )
774  return XRootDStatus( stError, errInvalidArgs, 0,
775  "cannot move directory to a subdirectory of itself." );
776 
777  //----------------------------------------------------------------------------
778  // Run the query
779  //----------------------------------------------------------------------------
780  XRootDStatus st = fs->Mv( fullPath1, fullPath2 );
781  if( !st.IsOK() )
782  {
783  log->Error( AppMsg, "Unable move %s to %s: %s",
784  fullPath1.c_str(), fullPath2.c_str(),
785  st.ToStr().c_str() );
786  return st;
787  }
788 
789  return XRootDStatus();
790 }
791 
792 //------------------------------------------------------------------------------
793 // Remove a file
794 //------------------------------------------------------------------------------
796  Env *env,
797  const FSExecutor::CommandParams &args )
798 {
799  //----------------------------------------------------------------------------
800  // Check up the args
801  //----------------------------------------------------------------------------
802  Log *log = DefaultEnv::GetLog();
803  uint32_t argc = args.size();
804 
805  if( argc < 2 )
806  {
807  log->Error( AppMsg, "Wrong number of arguments." );
809  }
810 
811  struct print_t
812  {
813  void print( const std::string &msg )
814  {
815  std::unique_lock<std::mutex> lck( mtx );
816  std::cout << msg << '\n';
817  }
818  std::mutex mtx;
819  };
820  std::shared_ptr<print_t> print;
821  if( argc - 1 > 0 )
822  print = std::make_shared<print_t>();
823 
824  std::vector<Pipeline> rms;
825  rms.reserve( argc - 1 );
826  for( size_t i = 1; i < argc; ++i )
827  {
828  std::string fullPath;
829  XRootDStatus pathSt = BuildPath( fullPath, env, args[i], "Removing" );
830  if( !pathSt.IsOK() )
831  return pathSt;
832  rms.emplace_back( Rm( fs, fullPath ) >>
833  [log, fullPath, print]( XRootDStatus &st )
834  {
835  if( !st.IsOK() )
836  {
837  log->Error( AppMsg, "Unable remove %s: %s",
838  fullPath.c_str(),
839  st.ToStr().c_str() );
840  }
841  if( print )
842  {
843  print->print( "rm " + fullPath + " : " + st.ToString() );
844  }
845  } );
846  }
847 
848  //----------------------------------------------------------------------------
849  // Run the query:
850  // Parallel() will take the vector of Pipeline by reference and empty the
851  // vector, so rms.size() will change after the call.
852  //----------------------------------------------------------------------------
853  const size_t rs = rms.size();
854  XRootDStatus st = WaitFor( Parallel( rms ).AtLeast( rs ) );
855  if( !st.IsOK() )
856  return st;
857 
858  return XRootDStatus();
859 }
860 
861 //------------------------------------------------------------------------------
862 // Truncate a file
863 //------------------------------------------------------------------------------
865  Env *env,
866  const FSExecutor::CommandParams &args )
867 {
868  //----------------------------------------------------------------------------
869  // Check up the args
870  //----------------------------------------------------------------------------
871  Log *log = DefaultEnv::GetLog();
872  uint32_t argc = args.size();
873 
874  if( argc != 3 )
875  {
876  log->Error( AppMsg, "Wrong number of arguments." );
878  }
879 
880  std::string fullPath;
881  XRootDStatus pathSt = BuildPath( fullPath, env, args[1], "Truncating" );
882  if( !pathSt.IsOK() )
883  return pathSt;
884 
885  char *result;
886  uint64_t size = ::strtoll( args[2].c_str(), &result, 0 );
887  if( *result != 0 )
888  {
889  log->Error( AppMsg, "Size parameter needs to be an integer" );
891  }
892 
893  //----------------------------------------------------------------------------
894  // Run the query
895  //----------------------------------------------------------------------------
896  XRootDStatus st = fs->Truncate( fullPath, size );
897  if( !st.IsOK() )
898  {
899  log->Error( AppMsg, "Unable truncate %s: %s",
900  fullPath.c_str(),
901  st.ToStr().c_str() );
902  return st;
903  }
904 
905  return XRootDStatus();
906 }
907 
908 //------------------------------------------------------------------------------
909 // Change the access rights to a file
910 //------------------------------------------------------------------------------
912  Env *env,
913  const FSExecutor::CommandParams &args )
914 {
915  //----------------------------------------------------------------------------
916  // Check up the args
917  //----------------------------------------------------------------------------
918  Log *log = DefaultEnv::GetLog();
919  uint32_t argc = args.size();
920 
921  if( argc != 3 )
922  {
923  log->Error( AppMsg, "Wrong number of arguments." );
925  }
926 
927  std::string fullPath;
928  XRootDStatus pathSt = BuildPath( fullPath, env, args[1], "Modifying" );
929  if( !pathSt.IsOK() )
930  return pathSt;
931 
932  Access::Mode mode = Access::None;
933  XRootDStatus st = ConvertMode( mode, args[2] );
934  if( !st.IsOK() )
935  {
936  log->Error( AppMsg, "Invalid mode string." );
937  return st;
938  }
939 
940  //----------------------------------------------------------------------------
941  // Run the query
942  //----------------------------------------------------------------------------
943  st = fs->ChMod( fullPath, mode );
944  if( !st.IsOK() )
945  {
946  log->Error( AppMsg, "Unable change mode of %s: %s",
947  fullPath.c_str(),
948  st.ToStr().c_str() );
949  return st;
950  }
951 
952  return XRootDStatus();
953 }
954 
955 //------------------------------------------------------------------------------
956 // Locate a path
957 //------------------------------------------------------------------------------
959  Env *env,
960  const FSExecutor::CommandParams &args )
961 {
962  //----------------------------------------------------------------------------
963  // Check up the args
964  //----------------------------------------------------------------------------
965  Log *log = DefaultEnv::GetLog();
966  uint32_t argc = args.size();
967 
968  if( argc > 4 )
969  {
970  log->Error( AppMsg, "Wrong number of arguments." );
972  }
973 
975  std::string path;
976  bool hasPath = false;
977  bool doDeepLocate = false;
978  for( uint32_t i = 1; i < argc; ++i )
979  {
980  if( args[i] == "-n" )
981  flags |= OpenFlags::NoWait;
982  else if( args[i] == "-r" )
983  flags |= OpenFlags::Refresh;
984  else if( args[i] == "-m" || args[i] == "-h" )
985  flags |= OpenFlags::PrefName;
986  else if( args[i] == "-i" )
987  flags |= OpenFlags::Force;
988  else if( args[i] == "-d" )
989  doDeepLocate = true;
990  else if( args[i] == "-p" )
991  {
992  Env *env = DefaultEnv::GetEnv();
993  env->PutInt( "PreserveLocateTried", 0 );
994  }
995  else if( !hasPath )
996  {
997  path = args[i];
998  hasPath = true;
999  }
1000  else
1001  {
1002  log->Error( AppMsg, "Invalid argument: %s.", args[i].c_str() );
1003  return XRootDStatus( stError, errInvalidArgs );
1004  }
1005  }
1006 
1007  std::string fullPath;
1008  if( path[0] == '*' )
1009  fullPath = path;
1010  else
1011  {
1012  XRootDStatus pathSt = BuildPath( fullPath, env, path, "Locating" );
1013  if( !pathSt.IsOK() )
1014  return pathSt;
1015  }
1016 
1017  //----------------------------------------------------------------------------
1018  // Run the query
1019  //----------------------------------------------------------------------------
1020  LocationInfo *info = 0;
1021  XRootDStatus st;
1022  if( doDeepLocate )
1023  st = fs->DeepLocate( fullPath, flags, info );
1024  else
1025  st = fs->Locate( fullPath, flags, info );
1026 
1027  if( !st.IsOK() )
1028  {
1029  log->Error( AppMsg, "Unable locate %s: %s",
1030  fullPath.c_str(),
1031  st.ToStr().c_str() );
1032  return st;
1033  }
1034 
1035  //----------------------------------------------------------------------------
1036  // Print the result
1037  //----------------------------------------------------------------------------
1038  if( st.code == suPartial )
1039  {
1040  std::cerr << "[!] Some of the requests failed. The result may be ";
1041  std::cerr << "incomplete." << std::endl;
1042  }
1043 
1045  for( it = info->Begin(); it != info->End(); ++it )
1046  {
1047  std::cout << it->GetAddress() << " ";
1048  switch( it->GetType() )
1049  {
1051  std::cout << "Manager ";
1052  break;
1054  std::cout << "ManagerPending ";
1055  break;
1057  std::cout << "Server ";
1058  break;
1060  std::cout << "ServerPending ";
1061  break;
1062  default:
1063  std::cout << "Unknown ";
1064  };
1065 
1066  switch( it->GetAccessType() )
1067  {
1068  case LocationInfo::Read:
1069  std::cout << "Read";
1070  break;
1072  std::cout << "ReadWrite ";
1073  break;
1074  default:
1075  std::cout << "Unknown ";
1076  };
1077  std::cout << std::endl;
1078  }
1079 
1080  delete info;
1081  return XRootDStatus();
1082 }
1083 
1084 //------------------------------------------------------------------------------
1085 // Process stat query
1086 //------------------------------------------------------------------------------
1087 XRootDStatus ProcessStatQuery( StatInfo &info, const std::string &query )
1088 {
1089  Log *log = DefaultEnv::GetLog();
1090 
1091  //----------------------------------------------------------------------------
1092  // Process the query
1093  //----------------------------------------------------------------------------
1094  bool isOrQuery = false;
1095  bool status = true;
1096  if( query.find( '|' ) != std::string::npos )
1097  {
1098  isOrQuery = true;
1099  status = false;
1100  }
1101  std::vector<std::string> queryFlags;
1102  if( isOrQuery )
1103  Utils::splitString( queryFlags, query, "|" );
1104  else
1105  Utils::splitString( queryFlags, query, "&" );
1106 
1107  //----------------------------------------------------------------------------
1108  // Initialize flag translation map and check the input flags
1109  //----------------------------------------------------------------------------
1110  std::map<std::string, StatInfo::Flags> flagMap;
1111  flagMap["XBitSet"] = StatInfo::XBitSet;
1112  flagMap["IsDir"] = StatInfo::IsDir;
1113  flagMap["Other"] = StatInfo::Other;
1114  flagMap["Offline"] = StatInfo::Offline;
1115  flagMap["POSCPending"] = StatInfo::POSCPending;
1116  flagMap["IsReadable"] = StatInfo::IsReadable;
1117  flagMap["IsWritable"] = StatInfo::IsWritable;
1118  flagMap["BackUpExists"] = StatInfo::BackUpExists;
1119 
1120  std::vector<std::string>::iterator it;
1121  for( it = queryFlags.begin(); it != queryFlags.end(); ++it )
1122  if( flagMap.find( *it ) == flagMap.end() )
1123  {
1124  log->Error( AppMsg, "Flag '%s' is not recognized.", it->c_str() );
1125  return XRootDStatus( stError, errInvalidArgs );
1126  }
1127 
1128  //----------------------------------------------------------------------------
1129  // Process the query
1130  //----------------------------------------------------------------------------
1131  if( isOrQuery )
1132  {
1133  for( it = queryFlags.begin(); it != queryFlags.end(); ++it )
1134  if( info.TestFlags( flagMap[*it] ) )
1135  return XRootDStatus();
1136  }
1137  else
1138  {
1139  for( it = queryFlags.begin(); it != queryFlags.end(); ++it )
1140  if( !info.TestFlags( flagMap[*it] ) )
1142  }
1143 
1144  if( status )
1145  return XRootDStatus();
1147 }
1148 
1149 //------------------------------------------------------------------------------
1150 // Stat a path
1151 //------------------------------------------------------------------------------
1153  Env *env,
1154  const FSExecutor::CommandParams &args )
1155 {
1156  //----------------------------------------------------------------------------
1157  // Check up the args
1158  //----------------------------------------------------------------------------
1159  Log *log = DefaultEnv::GetLog();
1160  uint32_t argc = args.size();
1161 
1162  if( argc < 2 )
1163  {
1164  log->Error( AppMsg, "Wrong number of arguments." );
1165  return XRootDStatus( stError, errInvalidArgs );
1166  }
1167 
1168  std::vector<std::string> paths;
1169  std::string query;
1170 
1171  for( uint32_t i = 1; i < args.size(); ++i )
1172  {
1173  if( args[i] == "-q" )
1174  {
1175  if( i < args.size()-1 )
1176  {
1177  query = args[i+1];
1178  ++i;
1179  }
1180  else
1181  {
1182  log->Error( AppMsg, "Parameter '-q' requires an argument." );
1183  return XRootDStatus( stError, errInvalidArgs );
1184  }
1185  }
1186  else
1187  paths.emplace_back( args[i] );
1188  }
1189 
1190  std::vector<XrdCl::Pipeline> stats;
1191  std::vector<std::tuple<std::future<StatInfo>, std::string>> results;
1192  for( auto &path : paths )
1193  {
1194  std::string fullPath;
1195  XRootDStatus pathSt = BuildPath( fullPath, env, path, "Stating" );
1196  if( !pathSt.IsOK() )
1197  return pathSt;
1198  std::future<XrdCl::StatInfo> ftr;
1199  stats.emplace_back( XrdCl::Stat( fs, fullPath ) >> ftr );
1200  results.emplace_back( std::move( ftr ), std::move( fullPath ) );
1201  }
1202 
1203  //----------------------------------------------------------------------------
1204  // Run the query
1205  //----------------------------------------------------------------------------
1206  XrdCl::Async( XrdCl::Parallel( stats ) );
1207 
1208  //----------------------------------------------------------------------------
1209  // Print the result
1210  //----------------------------------------------------------------------------
1212  for( auto &tpl : results )
1213  {
1214  auto &ftr = std::get<0>( tpl );
1215  auto &fullPath = std::get<1>( tpl );
1216  std::cout << std::endl;
1217  try
1218  {
1219  XrdCl::StatInfo info( ftr.get() );
1220  std::string flags;
1221 
1222  if( info.TestFlags( StatInfo::XBitSet ) )
1223  flags += "XBitSet|";
1224  if( info.TestFlags( StatInfo::IsDir ) )
1225  flags += "IsDir|";
1226  if( info.TestFlags( StatInfo::Other ) )
1227  flags += "Other|";
1228  if( info.TestFlags( StatInfo::Offline ) )
1229  flags += "Offline|";
1230  if( info.TestFlags( StatInfo::POSCPending ) )
1231  flags += "POSCPending|";
1232  if( info.TestFlags( StatInfo::IsReadable ) )
1233  flags += "IsReadable|";
1234  if( info.TestFlags( StatInfo::IsWritable ) )
1235  flags += "IsWritable|";
1236  if( info.TestFlags( StatInfo::BackUpExists ) )
1237  flags += "BackUpExists|";
1238 
1239  if( !flags.empty() )
1240  flags.erase( flags.length()-1, 1 );
1241 
1242  std::cout << "Path: " << fullPath << std::endl;
1243  std::cout << "Id: " << info.GetId() << std::endl;
1244  std::cout << "Size: " << info.GetSize() << std::endl;
1245  std::cout << "MTime: " << info.GetModTimeAsString() << std::endl;
1246  // if extended stat information is available we can print also
1247  // change time and access time
1248  if( info.ExtendedFormat() )
1249  {
1250  std::cout << "CTime: " << info.GetChangeTimeAsString() << std::endl;
1251  std::cout << "ATime: " << info.GetAccessTimeAsString() << std::endl;
1252  }
1253  std::cout << "Flags: " << info.GetFlags() << " (" << flags << ")";
1254 
1255  // check if extended stat information is available
1256  if( info.ExtendedFormat() )
1257  {
1258  std::cout << "\nMode: " << info.GetModeAsString() << std::endl;
1259  std::cout << "Owner: " << info.GetOwner() << std::endl;
1260  std::cout << "Group: " << info.GetGroup();
1261  }
1262 
1263  std::cout << std::endl;
1264 
1265  if( query.length() != 0 )
1266  {
1267  XRootDStatus s = ProcessStatQuery( info, query );
1268  if( !s.IsOK() )
1269  st = s;
1270  std::cout << "Query: " << query << " " << std::endl;
1271  }
1272  }
1273  catch( XrdCl::PipelineException &ex )
1274  {
1275  st = ex.GetError();
1276  log->Error( AppMsg, "Unable stat %s: %s", fullPath.c_str(), st.ToStr().c_str() );
1277  }
1278  }
1279 
1280  return st;
1281 }
1282 
1283 //------------------------------------------------------------------------------
1284 // Stat a VFS
1285 //------------------------------------------------------------------------------
1287  Env *env,
1288  const FSExecutor::CommandParams &args )
1289 {
1290  //----------------------------------------------------------------------------
1291  // Check up the args
1292  //----------------------------------------------------------------------------
1293  Log *log = DefaultEnv::GetLog();
1294  uint32_t argc = args.size();
1295 
1296  if( argc != 2 )
1297  {
1298  log->Error( AppMsg, "Wrong number of arguments." );
1299  return XRootDStatus( stError, errInvalidArgs );
1300  }
1301 
1302  std::string fullPath;
1303  XRootDStatus pathSt = BuildPath( fullPath, env, args[1], "Stating" );
1304  if( !pathSt.IsOK() )
1305  return pathSt;
1306 
1307  //----------------------------------------------------------------------------
1308  // Run the query
1309  //----------------------------------------------------------------------------
1310  StatInfoVFS *info = 0;
1311  XRootDStatus st = fs->StatVFS( fullPath, info );
1312 
1313  if( !st.IsOK() )
1314  {
1315  log->Error( AppMsg, "Unable stat VFS at %s: %s",
1316  fullPath.c_str(),
1317  st.ToStr().c_str() );
1318  return st;
1319  }
1320 
1321  //----------------------------------------------------------------------------
1322  // Print the result
1323  //----------------------------------------------------------------------------
1324  std::cout << "Path: ";
1325  std::cout << fullPath << std::endl;
1326  std::cout << "Nodes with RW space: ";
1327  std::cout << info->GetNodesRW() << std::endl;
1328  std::cout << "Size of largest RW space (MB): ";
1329  std::cout << info->GetFreeRW() << std::endl;
1330  std::cout << "Utilization of RW space (%): ";
1331  std::cout << (uint16_t)info->GetUtilizationRW() << std::endl;
1332  std::cout << "Nodes with staging space: ";
1333  std::cout << info->GetNodesStaging() << std::endl;
1334  std::cout << "Size of largest staging space (MB): ";
1335  std::cout << info->GetFreeStaging() << std::endl;
1336  std::cout << "Utilization of staging space (%): ";
1337  std::cout << (uint16_t)info->GetUtilizationStaging() << std::endl;
1338 
1339  delete info;
1340  return XRootDStatus();
1341 }
1342 
1343 //------------------------------------------------------------------------------
1344 // Query the server
1345 //------------------------------------------------------------------------------
1347  Env *env,
1348  const FSExecutor::CommandParams &args )
1349 {
1350  //----------------------------------------------------------------------------
1351  // Check up the args
1352  //----------------------------------------------------------------------------
1353  Log *log = DefaultEnv::GetLog();
1354  uint32_t argc = args.size();
1355 
1356  if( !( argc >= 3 ) )
1357  {
1358  log->Error( AppMsg, "Wrong number of arguments." );
1359  return XRootDStatus( stError, errInvalidArgs );
1360  }
1361 
1362  QueryCode::Code qCode;
1363  if( args[1] == "config" )
1364  qCode = QueryCode::Config;
1365  else if( args[1] == "checksumcancel" )
1366  qCode = QueryCode::ChecksumCancel;
1367  else if( args[1] == "checksum" )
1368  qCode = QueryCode::Checksum;
1369  else if( args[1] == "opaque" )
1370  qCode = QueryCode::Opaque;
1371  else if( args[1] == "opaquefile" )
1372  qCode = QueryCode::OpaqueFile;
1373  else if( args[1] == "prepare" )
1374  qCode = QueryCode::Prepare;
1375  else if( args[1] == "space" )
1376  qCode = QueryCode::Space;
1377  else if( args[1] == "stats" )
1378  qCode = QueryCode::Stats;
1379  else if( args[1] == "xattr" )
1380  qCode = QueryCode::XAttr;
1381  else
1382  {
1383  log->Error( AppMsg, "Invalid query code." );
1384  return XRootDStatus( stError, errInvalidArgs );
1385  }
1386 
1387  if( !( qCode & QueryCode::Prepare ) && argc != 3 )
1388  {
1389  log->Error( AppMsg, "Wrong number of arguments." );
1390  return XRootDStatus( stError, errInvalidArgs );
1391  }
1392 
1393  std::string strArg = args[2];
1394  if( qCode & QueryCode::Prepare )
1395  {
1396  // strArg is supposed to contain already the request ID
1397 
1398  for( size_t i = 3; i < args.size(); ++i )
1399  {
1400  std::string path = args[i];
1401  XRootDStatus pathSt = BuildPath( path, env, path, "Preparing" );
1402  if( !pathSt.IsOK() )
1403  return pathSt;
1404  // we use new line character as delimiter
1405  strArg += '\n';
1406  strArg += path;
1407  }
1408  }
1409  else
1410  {
1411  std::string strArg = args[2];
1412  if( qCode == QueryCode::ChecksumCancel ||
1413  qCode == QueryCode::Checksum ||
1414  qCode == QueryCode::XAttr )
1415  {
1416  XRootDStatus pathSt = BuildPath( strArg, env, args[2], "Querying" );
1417  if( !pathSt.IsOK() )
1418  return pathSt;
1419  }
1420  }
1421 
1422  //----------------------------------------------------------------------------
1423  // Run the query
1424  //----------------------------------------------------------------------------
1425  Buffer arg( strArg.size() );
1426  arg.FromString( strArg );
1427  Buffer *response = 0;
1428  XRootDStatus st = fs->Query( qCode, arg, response );
1429 
1430  if( !st.IsOK() )
1431  {
1432  log->Error( AppMsg, "Unable run query %s: %s",
1433  args[1].c_str(),
1434  st.ToStr().c_str() );
1435  return st;
1436  }
1437 
1438  //----------------------------------------------------------------------------
1439  // Print the result
1440  //----------------------------------------------------------------------------
1441  std::cout << response->ToString() << std::endl;
1442  delete response;
1443  return XRootDStatus();
1444 }
1445 
1446 //------------------------------------------------------------------------------
1447 // Query the server
1448 //------------------------------------------------------------------------------
1450  Env *env,
1451  const FSExecutor::CommandParams &args )
1452 {
1453  //----------------------------------------------------------------------------
1454  // Check up the args
1455  //----------------------------------------------------------------------------
1456  Log *log = DefaultEnv::GetLog();
1457  uint32_t argc = args.size();
1458 
1459  if( argc < 2 )
1460  {
1461  log->Error( AppMsg, "Wrong number of arguments." );
1462  return XRootDStatus( stError, errInvalidArgs );
1463  }
1464 
1466  std::vector<std::string> files;
1467  uint8_t priority = 0;
1468  std::string reqid;
1469 
1470  for( uint32_t i = 1; i < args.size(); ++i )
1471  {
1472  if( args[i] == "-p" )
1473  {
1474  if( i < args.size()-1 )
1475  {
1476  char *result;
1477  int32_t param = ::strtol( args[i+1].c_str(), &result, 0 );
1478  if( *result != 0 || param > 3 || param < 0 )
1479  {
1480  log->Error( AppMsg, "Size priotiry needs to be an integer between 0 "
1481  "and 3" );
1482  return XRootDStatus( stError, errInvalidArgs );
1483  }
1484  priority = (uint8_t)param;
1485  ++i;
1486  }
1487  else
1488  {
1489  log->Error( AppMsg, "Parameter '-p' requires an argument." );
1490  return XRootDStatus( stError, errInvalidArgs );
1491  }
1492  }
1493  else if( args[i] == "-c" )
1494  flags |= PrepareFlags::Colocate;
1495  else if( args[i] == "-f" )
1496  flags |= PrepareFlags::Fresh;
1497  else if( args[i] == "-s" )
1498  flags |= PrepareFlags::Stage;
1499  else if( args[i] == "-w" )
1500  flags |= PrepareFlags::WriteMode;
1501  else if( args[i] == "-e" )
1502  flags |= PrepareFlags::Evict;
1503  else if( args[i] == "-a" )
1504  {
1505  flags |= PrepareFlags::Cancel;
1506  if( i < args.size()-1 )
1507  {
1508  // by convention the request ID appears as the the first token
1509  // in the list of files
1510  files.push_back( args[i+1] );
1511  ++i;
1512  }
1513  else
1514  {
1515  log->Error( AppMsg, "Parameter '-a' requires an argument." );
1516  return XRootDStatus( stError, errInvalidArgs );
1517  }
1518  }
1519  else
1520  files.push_back( args[i] );
1521  }
1522 
1523  if( files.empty() )
1524  {
1525  log->Error( AppMsg, "Filename missing." );
1526  return XRootDStatus( stError, errInvalidArgs );
1527  }
1528 
1529  //----------------------------------------------------------------------------
1530  // Run the command
1531  //----------------------------------------------------------------------------
1532  Buffer *response = 0;
1533  XRootDStatus st = fs->Prepare( files, flags, priority, response );
1534  if( !st.IsOK() )
1535  {
1536  log->Error( AppMsg, "Prepare request failed: %s", st.ToStr().c_str() );
1537  return st;
1538  }
1539 
1540  if( ( flags & PrepareFlags::Stage ) && response )
1541  {
1542  std::cout << response->ToString() << '\n';
1543  }
1544 
1545  delete response;
1546  return XRootDStatus();
1547 }
1548 
1549 //------------------------------------------------------------------------------
1550 // Copy progress handler
1551 //------------------------------------------------------------------------------
1553 {
1554  public:
1555  //--------------------------------------------------------------------------
1556  // Constructor
1557  //--------------------------------------------------------------------------
1558  ProgressDisplay(): pBytesProcessed(0), pBytesTotal(0), pPrevious(0)
1559  {}
1560 
1561  //--------------------------------------------------------------------------
1562  // End job
1563  //--------------------------------------------------------------------------
1564  virtual void EndJob( uint32_t jobNum, const XrdCl::PropertyList *results )
1565  {
1566  JobProgress( jobNum, pBytesProcessed, pBytesTotal );
1567  std::cerr << std::endl;
1568  }
1569 
1570  //--------------------------------------------------------------------------
1571  // Job progress
1572  //--------------------------------------------------------------------------
1573  virtual void JobProgress( uint32_t jobNum,
1574  uint64_t bytesProcessed,
1575  uint64_t bytesTotal )
1576  {
1577  pBytesProcessed = bytesProcessed;
1578  pBytesTotal = bytesTotal;
1579 
1580  time_t now = time(0);
1581  if( (now - pPrevious < 1) && (bytesProcessed != bytesTotal) )
1582  return;
1583  pPrevious = now;
1584 
1585  std::cerr << "\r";
1586  std::cerr << "Progress: ";
1587  std::cerr << XrdCl::Utils::BytesToString(bytesProcessed) << "B ";
1588 
1589  if( bytesTotal )
1590  std::cerr << "(" << bytesProcessed*100/bytesTotal << "%)";
1591 
1592  std::cerr << std::flush;
1593  }
1594 
1595  private:
1596  uint64_t pBytesProcessed;
1597  uint64_t pBytesTotal;
1598  time_t pPrevious;
1599 };
1600 
1601 //------------------------------------------------------------------------------
1602 // Cat a file
1603 //------------------------------------------------------------------------------
1605  Env *env,
1606  const FSExecutor::CommandParams &args )
1607 {
1608  //----------------------------------------------------------------------------
1609  // Check up the args
1610  //----------------------------------------------------------------------------
1611  Log *log = DefaultEnv::GetLog();
1612  uint32_t argc = args.size();
1613 
1614  if( argc < 2 )
1615  {
1616  log->Error( AppMsg, "Wrong number of arguments." );
1617  return XRootDStatus( stError, errInvalidArgs );
1618  }
1619 
1620  std::string server;
1621  env->GetString( "ServerURL", server );
1622  if( server.empty() )
1623  {
1624  log->Error( AppMsg, "Invalid address: \"%s\".", server.c_str() );
1625  return XRootDStatus( stError, errInvalidAddr );
1626  }
1627 
1628  std::vector<std::string> remotes;
1629  std::string local;
1630 
1631  for( uint32_t i = 1; i < args.size(); ++i )
1632  {
1633  if( args[i] == "-o" )
1634  {
1635  if( i < args.size()-1 )
1636  {
1637  local = args[i+1];
1638  ++i;
1639  }
1640  else
1641  {
1642  log->Error( AppMsg, "Parameter '-o' requires an argument." );
1643  return XRootDStatus( stError, errInvalidArgs );
1644  }
1645  }
1646  else
1647  remotes.emplace_back( args[i] );
1648  }
1649 
1650  if( !local.empty() && remotes.size() > 1 )
1651  {
1652  log->Error( AppMsg, "If '-o' is used only can be used with only one remote file." );
1653  return XRootDStatus( stError, errInvalidArgs );
1654  }
1655 
1656  std::vector<URL> remoteUrls;
1657  remoteUrls.reserve( remotes.size() );
1658  for( auto &remote : remotes )
1659  {
1660  std::string remoteFile;
1661  XRootDStatus pathSt = BuildPath( remoteFile, env, remote, "Opening" );
1662  if( !pathSt.IsOK() )
1663  return pathSt;
1664 
1665  remoteUrls.emplace_back( server );
1666  remoteUrls.back().SetPath( remoteFile );
1667  }
1668 
1669  //----------------------------------------------------------------------------
1670  // Fetch the data
1671  //----------------------------------------------------------------------------
1672  CopyProgressHandler *handler = 0; ProgressDisplay d;
1673  CopyProcess process;
1674  std::vector<PropertyList> props( remoteUrls.size() ), results( remoteUrls.size() );
1675 
1676  for( size_t i = 0; i < remoteUrls.size(); ++i )
1677  {
1678  props[i].Set( "source", remoteUrls[i].GetURL() );
1679  if( !local.empty() )
1680  {
1681  props[i].Set( "target", std::string( "file://" ) + local );
1682  handler = &d;
1683  }
1684  else
1685  props[i].Set( "target", "stdio://-" );
1686 
1687  props[i].Set( "dynamicSource", true );
1688 
1689  XRootDStatus st = process.AddJob( props[i], &results[i] );
1690  if( !st.IsOK() )
1691  {
1692  log->Error( AppMsg, "Job adding failed: %s.", st.ToStr().c_str() );
1693  return st;
1694  }
1695  }
1696 
1697  XRootDStatus st = process.Prepare();
1698  if( !st.IsOK() )
1699  {
1700  log->Error( AppMsg, "Copy preparation failed: %s.", st.ToStr().c_str() );
1701  return st;
1702  }
1703 
1704  st = process.Run(handler);
1705  if( !st.IsOK() )
1706  {
1707  log->Error( AppMsg, "Cope process failed: %s.", st.ToStr().c_str() );
1708  return st;
1709  }
1710 
1711  return XRootDStatus();
1712 }
1713 
1714 //------------------------------------------------------------------------------
1715 // Tail a file
1716 //------------------------------------------------------------------------------
1718  Env *env,
1719  const FSExecutor::CommandParams &args )
1720 {
1721  //----------------------------------------------------------------------------
1722  // Check up the args
1723  //----------------------------------------------------------------------------
1724  Log *log = DefaultEnv::GetLog();
1725  uint32_t argc = args.size();
1726 
1727  if( argc < 2 || argc > 5 )
1728  {
1729  log->Error( AppMsg, "Wrong number of arguments." );
1730  return XRootDStatus( stError, errInvalidArgs );
1731  }
1732 
1733  std::string server;
1734  env->GetString( "ServerURL", server );
1735  if( server.empty() )
1736  {
1737  log->Error( AppMsg, "Invalid address: \"%s\".", server.c_str() );
1738  return XRootDStatus( stError, errInvalidAddr );
1739  }
1740 
1741  std::string remote;
1742  bool followMode = false;
1743  uint32_t offset = 512;
1744 
1745  for( uint32_t i = 1; i < args.size(); ++i )
1746  {
1747  if( args[i] == "-f" )
1748  followMode = true;
1749  else if( args[i] == "-c" )
1750  {
1751  if( i < args.size()-1 )
1752  {
1753  char *result;
1754  offset = ::strtol( args[i+1].c_str(), &result, 0 );
1755  if( *result != 0 )
1756  {
1757  log->Error( AppMsg, "Offset from the end needs to be a number: %s",
1758  args[i+1].c_str() );
1759  return XRootDStatus( stError, errInvalidArgs );
1760  }
1761  ++i;
1762  }
1763  else
1764  {
1765  log->Error( AppMsg, "Parameter '-n' requires an argument." );
1766  return XRootDStatus( stError, errInvalidArgs );
1767  }
1768  }
1769  else
1770  remote = args[i];
1771  }
1772 
1773  std::string remoteFile;
1774  XRootDStatus pathSt = BuildPath( remoteFile, env, remote, "Opening" );
1775  if( !pathSt.IsOK() )
1776  return pathSt;
1777 
1778  URL remoteUrl( server );
1779  remoteUrl.SetPath( remoteFile );
1780 
1781  //----------------------------------------------------------------------------
1782  // Fetch the data
1783  //----------------------------------------------------------------------------
1784  File file;
1785  XRootDStatus st = file.Open( remoteUrl.GetURL(), OpenFlags::Read );
1786  if( !st.IsOK() )
1787  {
1788  log->Error( AppMsg, "Unable to open file %s: %s",
1789  remoteUrl.GetObfuscatedURL().c_str(), st.ToStr().c_str() );
1790  return st;
1791  }
1792 
1793  StatInfo *info = 0;
1794  uint64_t size = 0;
1795  st = file.Stat( false, info );
1796  if (st.IsOK()) size = info->GetSize();
1797 
1798  if( size < offset )
1799  offset = 0;
1800  else
1801  offset = size - offset;
1802 
1803  uint32_t chunkSize = 1*1024*1024;
1804  char *buffer = new char[chunkSize];
1805  uint32_t bytesRead = 0;
1806  while(1)
1807  {
1808  st = file.Read( offset, chunkSize, buffer, bytesRead );
1809  if( !st.IsOK() )
1810  {
1811  log->Error( AppMsg, "Unable to read from %s: %s",
1812  remoteUrl.GetObfuscatedURL().c_str(), st.ToStr().c_str() );
1813  delete [] buffer;
1814  return st;
1815  }
1816 
1817  offset += bytesRead;
1818  int ret = write( 1, buffer, bytesRead );
1819  if( ret == -1 )
1820  {
1821  log->Error( AppMsg, "Unable to write to stdout: %s",
1822  XrdSysE2T(errno) );
1823  delete [] buffer;
1824  return st;
1825  }
1826 
1827  if( bytesRead < chunkSize )
1828  {
1829  if( !followMode )
1830  break;
1831  sleep(1);
1832  }
1833  }
1834  delete [] buffer;
1835 
1836  XRootDStatus stC = file.Close();
1837 
1838  return XRootDStatus();
1839 }
1840 
1841 //------------------------------------------------------------------------------
1842 // Print statistics concerning given space
1843 //------------------------------------------------------------------------------
1845  Env *env,
1846  const FSExecutor::CommandParams &args )
1847 {
1848  using namespace XrdCl;
1849 
1850  //----------------------------------------------------------------------------
1851  // Check up the args
1852  //----------------------------------------------------------------------------
1853  Log *log = DefaultEnv::GetLog();
1854  uint32_t argc = args.size();
1855 
1856  if( argc != 2 )
1857  {
1858  log->Error( AppMsg, "Wrong number of arguments." );
1859  return XRootDStatus( stError, errInvalidArgs );
1860  }
1861 
1863 
1864  XRootDStatus st = FileSystemUtils::GetSpaceInfo( i, fs, args[1] );
1865  if( !st.IsOK() )
1866  return st;
1867 
1868  if( st.code == suPartial )
1869  {
1870  std::cerr << "[!] Some of the requests failed. The result may be ";
1871  std::cerr << "incomplete." << std::endl;
1872  }
1873 
1874  std::cout << "Path: " << args[1] << std::endl;
1875  std::cout << "Total: " << i->GetTotal() << std::endl;
1876  std::cout << "Free: " << i->GetFree() << std::endl;
1877  std::cout << "Used: " << i->GetUsed() << std::endl;
1878  std::cout << "Largest free chunk: " << i->GetLargestFreeChunk() << std::endl;
1879 
1880  delete i;
1881  return XRootDStatus();
1882 }
1883 
1884 //------------------------------------------------------------------------------
1885 // Carry out xattr operation
1886 //------------------------------------------------------------------------------
1888  Env *env,
1889  const FSExecutor::CommandParams &args )
1890 {
1891  //----------------------------------------------------------------------------
1892  // Check up the args
1893  //----------------------------------------------------------------------------
1894  Log *log = DefaultEnv::GetLog();
1895  uint32_t argc = args.size();
1896 
1897  if( argc < 3 )
1898  {
1899  log->Error( AppMsg, "Wrong number of arguments." );
1900  return XRootDStatus( stError, errInvalidArgs );
1901  }
1902 
1903  kXR_char code = 0;
1904  if( args[2] == "set")
1905  code = kXR_fattrSet;
1906  else if( args[2] == "get" )
1907  code = kXR_fattrGet;
1908  else if( args[2] == "del" )
1909  code = kXR_fattrDel;
1910  else if( args[2] == "list" )
1911  code = kXR_fattrList;
1912  else
1913  {
1914  log->Error( AppMsg, "Invalid xattr code." );
1915  return XRootDStatus( stError, errInvalidArgs );
1916  }
1917 
1918  std::string path;
1919  XRootDStatus pathSt = BuildPath( path, env, args[1], "Accessing" );
1920  if( !pathSt.IsOK() )
1921  return pathSt;
1922 
1923  //----------------------------------------------------------------------------
1924  // Issue the xattr operation
1925  //----------------------------------------------------------------------------
1926  XRootDStatus status;
1927  switch( code )
1928  {
1929  case kXR_fattrSet:
1930  {
1931  if( argc != 4 )
1932  {
1933  log->Error( AppMsg, "Wrong number of arguments." );
1934  return XRootDStatus( stError, errInvalidArgs );
1935  }
1936 
1937  std::string key_value = args[3];
1938  size_t pos = key_value.find( '=' );
1939  std::string key = key_value.substr( 0, pos );
1940  std::string value = key_value.substr( pos + 1 );
1941  std::vector<xattr_t> attrs;
1942  attrs.push_back( std::make_tuple( key, value ) );
1943 
1944  std::vector<XAttrStatus> result;
1945  XRootDStatus status = fs->SetXAttr( path, attrs, result );
1946  XAttrStatus xst = status.IsOK() ? result.front() : XAttrStatus( key, status );
1947 
1948  if( !xst.status.IsOK() )
1949  status = xst.status;
1950 
1951  if( !status.IsOK() )
1952  log->Error( AppMsg, "Unable to xattr set %s %s: %s",
1953  key.c_str(), value.c_str(),
1954  status.ToStr().c_str() );
1955  return status;
1956  }
1957 
1958  case kXR_fattrGet:
1959  {
1960  if( argc != 4 )
1961  {
1962  log->Error( AppMsg, "Wrong number of arguments." );
1963  return XRootDStatus( stError, errInvalidArgs );
1964  }
1965 
1966  std::string key = args[3];
1967  std::vector<std::string> attrs;
1968  attrs.push_back( key );
1969 
1970  std::vector<XAttr> result;
1971  XRootDStatus status = fs->GetXAttr( path, attrs, result );
1972  XAttr xattr = status.IsOK() ? result.front() : XAttr( key, status );
1973 
1974  if( !xattr.status.IsOK() )
1975  status = xattr.status;
1976 
1977  if( !status.IsOK() )
1978  log->Error( AppMsg, "Unable to xattr get %s : %s",
1979  key.c_str(),
1980  status.ToStr().c_str() );
1981  else
1982  {
1983  std::cout << "# file: " << path << '\n';
1984  std::cout << xattr.name << "=\"" << xattr.value << "\"\n";
1985  }
1986 
1987  return status;
1988  }
1989 
1990  case kXR_fattrDel:
1991  {
1992  if( argc != 4 )
1993  {
1994  log->Error( AppMsg, "Wrong number of arguments." );
1995  return XRootDStatus( stError, errInvalidArgs );
1996  }
1997 
1998  std::string key = args[3];
1999  std::vector<std::string> attrs;
2000  attrs.push_back( key );
2001 
2002  std::vector<XAttrStatus> result ;
2003  XRootDStatus status = fs->DelXAttr( path, attrs, result );
2004  XAttrStatus xst = status.IsOK() ? result.front() : XAttrStatus( key, status );
2005 
2006  if( !xst.status.IsOK() )
2007  status = xst.status;
2008 
2009  if( !status.IsOK() )
2010  log->Error( AppMsg, "Unable to xattr del %s : %s",
2011  key.c_str(),
2012  status.ToStr().c_str() );
2013  return status;
2014  }
2015 
2016  case kXR_fattrList:
2017  {
2018  if( argc != 3 )
2019  {
2020  log->Error( AppMsg, "Wrong number of arguments." );
2021  return XRootDStatus( stError, errInvalidArgs );
2022  }
2023 
2024  std::vector<XAttr> result;
2025  XRootDStatus status = fs->ListXAttr( path, result );
2026 
2027  if( !status.IsOK() )
2028  log->Error( AppMsg, "Unable to xattr list : %s",
2029  status.ToStr().c_str() );
2030  else
2031  {
2032  std::cout << "# file: " << path << '\n';
2033  auto itr = result.begin();
2034  for( ; itr != result.end(); ++itr )
2035  std::cout << itr->name << "=\"" << itr->value << "\"\n";
2036  }
2037 
2038  return status;
2039  }
2040 
2041  default:
2042  return XRootDStatus( stError, errInvalidAddr );
2043  }
2044 }
2045 
2046 //------------------------------------------------------------------------------
2047 // Print help
2048 //------------------------------------------------------------------------------
2050  const FSExecutor::CommandParams & )
2051 {
2052  printf( "Usage:\n" );
2053  printf( " xrdfs [options] host[:port] - interactive mode\n" );
2054  printf( " xrdfs [options] host[:port] command args - server-first batch\n" );
2055  printf( " xrdfs [options] command args-with-URLs - command-first batch\n\n" );
2056 
2057  printf( "The two batch forms cannot be mixed.\n\n" );
2058 
2059  printf( "Available options:\n\n" );
2060 
2061  printf( " -4, --ipv4 use only the IPv4 network stack\n" );
2062  printf( " -6, --ipv6 use only the IPv6 network stack\n" );
2063  printf( " -d, --debug <level> set debug level: 0 off, 1 low, 2 medium,\n" );
2064  printf( " 3 high\n" );
2065  printf( " -h, --help show this help\n" );
2066  printf( " --no-cwd do not preset a CWD in interactive mode\n\n" );
2067 
2068  printf( "Available commands:\n\n" );
2069 
2070  printf( " exit\n" );
2071  printf( " Exits from the program.\n\n" );
2072 
2073  printf( " help\n" );
2074  printf( " This help screen.\n\n" );
2075 
2076  printf( " cache {evict | fevict} <path>\n" );
2077  printf( " Evict a file from a cache if not in use; while fevict\n" );
2078  printf( " forcibly evicts the file causing any current uses of the\n" );
2079  printf( " file to get read failures on a subsequent read\n\n" );
2080 
2081  printf( " cd <path>\n" );
2082  printf( " Change the current working directory\n\n" );
2083 
2084  printf( " chmod <path> <user><group><other>\n" );
2085  printf( " Modify permissions. Permission string example:\n" );
2086  printf( " rwxr-x--x\n\n" );
2087 
2088  printf( " ls [-l] [-u] [-R] [-D] [-Z] [-C] [dirname]\n" );
2089  printf( " Get directory listing.\n" );
2090  printf( " -l stat every entry and print long listing\n" );
2091  printf( " -u print paths as URLs\n" );
2092  printf( " -R list subdirectories recursively\n" );
2093  printf( " -D show duplicate entries\n" );
2094  printf( " -Z if a ZIP archive list its content\n" );
2095  printf( " -C checksum every entry\n\n" );
2096 
2097  printf( " locate [-n] [-r] [-d] [-m] [-i] [-p] <path>\n" );
2098  printf( " Get the locations of the path.\n" );
2099  printf( " -r refresh, don't use cached locations\n" );
2100  printf( " -n make the server return the response immediately even\n" );
2101  printf( " though it may be incomplete\n" );
2102  printf( " -d do a recursive (deep) locate\n" );
2103  printf( " -m|-h prefer host names to IP addresses\n" );
2104  printf( " -i ignore network dependencies\n" );
2105  printf( " -p be passive: ignore tried/triedrc cgi opaque info\n\n" );
2106 
2107  printf( " mkdir [-p] [-m<user><group><other>] <dirname>\n" );
2108  printf( " Creates a directory/tree of directories.\n\n" );
2109 
2110  printf( " mv <path1> <path2>\n" );
2111  printf( " Move path1 to path2 locally on the same server.\n\n" );
2112 
2113  printf( " stat [-q query] <path>\n" );
2114  printf( " Get info about the file or directory.\n" );
2115  printf( " -q query optional flag query parameter that makes\n" );
2116  printf( " xrdfs return error code to the shell if the\n" );
2117  printf( " requested flag combination is not present;\n" );
2118  printf( " flags may be combined together using '|' or '&'\n" );
2119  printf( " Available flags:\n" );
2120  printf( " XBitSet, IsDir, Other, Offline, POSCPending,\n" );
2121  printf( " IsReadable, IsWritable\n\n" );
2122 
2123  printf( " statvfs <path>\n" );
2124  printf( " Get info about a virtual file system.\n\n" );
2125 
2126  printf( " query <code> <parameters>\n" );
2127  printf( " Obtain server information. Query codes:\n\n" );
2128 
2129  printf( " config <what> Server configuration; <what> is\n" );
2130  printf( " one of the following:\n" );
2131  printf( " bind_max - the maximum number of parallel streams\n" );
2132  printf( " chksum - the supported checksum\n" );
2133  printf( " cms - the status of the cmsd\n" );
2134  printf( " pio_max - maximum number of parallel I/O requests\n" );
2135  printf( " readv_ior_max - maximum size of a readv element\n" );
2136  printf( " readv_iov_max - maximum number of readv entries\n" );
2137  printf( " role - the role in a cluster\n" );
2138  printf( " sitename - the site name\n" );
2139  printf( " tpc - support for third party copies\n" );
2140  printf( " version - the version of the server\n" );
2141  printf( " wan_port - the port to use for wan copies\n" );
2142  printf( " wan_window - the wan_port window size\n" );
2143  printf( " window - the tcp window size\n" );
2144  printf( " checksumcancel <path> File checksum cancellation\n" );
2145  printf( " checksum <path> File checksum\n" );
2146  printf( " opaque <arg> Implementation dependent\n" );
2147  printf( " opaquefile <arg> Implementation dependent\n" );
2148  printf( " space <space> Logical space stats\n" );
2149  printf( " stats <what> Server stats; <what> is a list\n" );
2150  printf( " of letters indicating information\n");
2151  printf( " to be returned:\n" );
2152  printf( " a - all statistics\n" );
2153  printf( " p - protocol statistics\n" );
2154  printf( " b - buffer usage statistics\n" );
2155  printf( " s - scheduling statistics\n" );
2156  printf( " d - device polling statistics\n" );
2157  printf( " u - usage statistics\n" );
2158  printf( " i - server identification\n" );
2159  printf( " z - synchronized statistics\n" );
2160  printf( " l - connection statistics\n" );
2161  printf( " xattr <path> Extended attributes\n" );
2162  printf( " prepare <reqid> [filenames] Prepare request status\n\n" );
2163 
2164  printf( " rm <filename>\n" );
2165  printf( " Remove a file.\n\n" );
2166 
2167  printf( " rmdir <dirname>\n" );
2168  printf( " Remove a directory.\n\n" );
2169 
2170  printf( " truncate <filename> <length>\n" );
2171  printf( " Truncate a file.\n\n" );
2172 
2173  printf( " prepare [-c] [-f] [-s] [-w] [-e] [-p priority] [-a requestid] filenames\n" );
2174  printf( " Prepare one or more files for access.\n" );
2175  printf( " -c co-locate staged files if possible\n" );
2176  printf( " -f refresh file access time even if the location is known\n" );
2177  printf( " -s stage the files to disk if they are not online\n" );
2178  printf( " -w the files will be accessed for modification\n" );
2179  printf( " -p priority of the request, 0 (lowest) - 3 (highest)\n" );
2180  printf( " -a abort stage request\n" );
2181  printf( " -e evict the file from disk cache\n\n" );
2182 
2183  printf( " cat [-o local file] files\n" );
2184  printf( " Print contents of one or more files to stdout.\n" );
2185  printf( " -o print to the specified local file\n\n" );
2186 
2187  printf( " tail [-c bytes] [-f] file\n" );
2188  printf( " Output last part of files to stdout.\n" );
2189  printf( " -c num_bytes out last num_bytes\n" );
2190  printf( " -f output appended data as file grows\n\n" );
2191 
2192  printf( " spaceinfo path\n" );
2193  printf( " Get space statistics for given path.\n\n" );
2194 
2195  printf( " xattr <path> <code> <params> \n" );
2196  printf( " Operation on extended attributes. Codes:\n\n" );
2197  printf( " set <attr> Set extended attribute; <attr> is\n" );
2198  printf( " string of form name=value\n" );
2199  printf( " get <name> Get extended attribute\n" );
2200  printf( " del <name> Delete extended attribute\n" );
2201  printf( " list List extended attributes\n\n" );
2202 
2203  return XRootDStatus();
2204 }
2205 
2206 //------------------------------------------------------------------------------
2207 // Create the executor object
2208 //------------------------------------------------------------------------------
2210 {
2211  Env *env = new Env();
2212  env->PutString( "CWD", "/" );
2213  FSExecutor *executor = new FSExecutor( url, env );
2214  executor->AddCommand( "cache", DoCache );
2215  executor->AddCommand( "cd", DoCD );
2216  executor->AddCommand( "chmod", DoChMod );
2217  executor->AddCommand( "ls", DoLS );
2218  executor->AddCommand( "help", PrintHelp );
2219  executor->AddCommand( "stat", DoStat );
2220  executor->AddCommand( "statvfs", DoStatVFS );
2221  executor->AddCommand( "locate", DoLocate );
2222  executor->AddCommand( "mv", DoMv );
2223  executor->AddCommand( "mkdir", DoMkDir );
2224  executor->AddCommand( "rm", DoRm );
2225  executor->AddCommand( "rmdir", DoRmDir );
2226  executor->AddCommand( "query", DoQuery );
2227  executor->AddCommand( "truncate", DoTruncate );
2228  executor->AddCommand( "prepare", DoPrepare );
2229  executor->AddCommand( "cat", DoCat );
2230  executor->AddCommand( "tail", DoTail );
2231  executor->AddCommand( "spaceinfo", DoSpaceInfo );
2232  executor->AddCommand( "xattr", DoXAttr );
2233  return executor;
2234 }
2235 
2236 //------------------------------------------------------------------------------
2237 // Execute command
2238 //------------------------------------------------------------------------------
2240 {
2241  XRootDStatus st = ex->Execute( args );
2242  if( !st.IsOK() )
2243  std::cerr << st.ToStr() << std::endl;
2244  return st.GetShellCode();
2245 }
2246 
2247 //------------------------------------------------------------------------------
2248 // Define some functions required to function when build without readline
2249 //------------------------------------------------------------------------------
2250 #ifndef HAVE_READLINE
2251 char *readline(const char *prompt)
2252 {
2253  std::cout << prompt << std::flush;
2254  std::string input;
2255  std::getline( std::cin, input );
2256 
2257  if( !std::cin.good() )
2258  return 0;
2259 
2260  char *linebuf = (char *)malloc( input.size()+1 );
2261  strncpy( linebuf, input.c_str(), input.size()+1 );
2262 
2263  return linebuf;
2264 }
2265 
2266 void add_history( const char * )
2267 {
2268 }
2269 
2270 void rl_bind_key( char, uint16_t )
2271 {
2272 }
2273 
2274 uint16_t rl_insert = 0;
2275 
2276 int read_history( const char * )
2277 {
2278  return 0;
2279 }
2280 
2281 int write_history( const char * )
2282 {
2283  return 0;
2284 }
2285 #endif
2286 
2287 //------------------------------------------------------------------------------
2288 // Build the command prompt
2289 //------------------------------------------------------------------------------
2290 std::string BuildPrompt( Env *env, const URL &url )
2291 {
2292  std::ostringstream prompt;
2293  std::string cwd = "/";
2294  env->GetString( "CWD", cwd );
2295  prompt << "[" << url.GetHostId() << "] " << cwd << " > ";
2296  return prompt.str();
2297 }
2298 
2299 //------------------------------------------------------------------------
2305 //------------------------------------------------------------------------
2306 bool getArguments (std::vector<std::string> & result, const std::string &input)
2307 {
2308  // the delimiter (space in the case of command line)
2309  static const char delimiter = ' ';
2310  // two types of quotes: single and double quotes
2311  const char singleQuote = '\'', doubleQuote = '\"';
2312  // if the current character of the command has been
2313  // quoted 'currentQuote' holds the type of quote,
2314  // otherwise it holds the null character
2315  char currentQuote = '\0';
2316 
2317  std::string tmp;
2318  for (std::string::const_iterator it = input.begin (); it != input.end (); ++it)
2319  {
2320  // if we encountered a quote character ...
2321  if (*it == singleQuote || *it == doubleQuote)
2322  {
2323  // if we are not within quoted text ...
2324  if (!currentQuote)
2325  {
2326  currentQuote = *it; // set the type of quote
2327  continue; // and continue, the quote character itself is not a part of the parameter
2328  }
2329  // otherwise if it is the closing quote character ...
2330  else if (currentQuote == *it)
2331  {
2332  currentQuote = '\0'; // reset the current quote type
2333  continue; // and continue, the quote character itself is not a part of the parameter
2334  }
2335  }
2336  // if we are within quoted text or the character is not a delimiter ...
2337  if (currentQuote || *it != delimiter)
2338  {
2339  // concatenate it
2340  tmp += *it;
2341  }
2342  else
2343  {
2344  // otherwise add a parameter and erase the tmp string
2345  if (!tmp.empty ())
2346  {
2347  result.push_back(tmp);
2348  tmp.erase ();
2349  }
2350  }
2351  }
2352  // if the there are some remainders of the command add them
2353  if (!tmp.empty())
2354  {
2355  result.push_back(tmp);
2356  }
2357  // return true if the quotation has been closed
2358  return currentQuote == '\0';
2359 }
2360 
2361 //------------------------------------------------------------------------------
2362 // Execute interactive
2363 //------------------------------------------------------------------------------
2364 int ExecuteInteractive( const URL &url, bool noCwd = false )
2365 {
2366  //----------------------------------------------------------------------------
2367  // Set up the environment
2368  //----------------------------------------------------------------------------
2369  std::string historyFile = getenv( "HOME" );
2370  historyFile += "/.xrdquery.history";
2371  rl_bind_key( '\t', rl_insert );
2372  read_history( historyFile.c_str() );
2373  FSExecutor *ex = CreateExecutor( url );
2374 
2375  if( noCwd )
2376  ex->GetEnv()->PutInt( "NoCWD", 1 );
2377 
2378  //----------------------------------------------------------------------------
2379  // Execute the commands
2380  //----------------------------------------------------------------------------
2381  std::string cmdline;
2382  while(1)
2383  {
2384  char *linebuf = 0;
2385  // print new prompt only if the previous line was complete
2386  // (a line is considered not to be complete if a quote has
2387  // been opened but it has not been closed)
2388  linebuf = readline( cmdline.empty() ? BuildPrompt( ex->GetEnv(), url ).c_str() : "> " );
2389  if( !linebuf || !strncmp( linebuf, "exit", 4 ) || !strncmp( linebuf, "quit", 4 ) )
2390  {
2391  std::cout << "Goodbye." << std::endl << std::endl;
2392  break;
2393  }
2394  if( !*linebuf)
2395  {
2396  free( linebuf );
2397  continue;
2398  }
2399  std::vector<std::string> args;
2400  cmdline += linebuf;
2401  free( linebuf );
2402  if (getArguments( args, cmdline ))
2403  {
2404  XRootDStatus st = ex->Execute( args );
2405  add_history( cmdline.c_str() );
2406  cmdline.erase();
2407  if( !st.IsOK() )
2408  std::cerr << st.ToStr() << std::endl;
2409  }
2410  }
2411 
2412  //----------------------------------------------------------------------------
2413  // Cleanup
2414  //----------------------------------------------------------------------------
2415  delete ex;
2416  write_history( historyFile.c_str() );
2417  return 0;
2418 }
2419 
2420 //------------------------------------------------------------------------------
2421 // Execute command
2422 //------------------------------------------------------------------------------
2423 int ExecuteCommand( const URL &url, const FSExecutor::CommandParams &args )
2424 {
2425  FSExecutor *ex = CreateExecutor( url );
2426  ex->GetEnv()->PutInt( "NoCWD", 1 );
2427  int st = ExecuteCommand( ex, args );
2428  delete ex;
2429  return st;
2430 }
2431 
2432 //------------------------------------------------------------------------------
2433 // Start the show
2434 //------------------------------------------------------------------------------
2435 int main( int argc, char **argv )
2436 {
2438  enum { NoCwdOption = 256 };
2439  static const option options[] = {
2440  { "ipv4", no_argument, 0, '4' },
2441  { "ipv6", no_argument, 0, '6' },
2442  { "debug", required_argument, 0, 'd' },
2443  { "help", no_argument, 0, 'h' },
2444  { "no-cwd", no_argument, 0, NoCwdOption },
2445  { 0, 0, 0, 0 }
2446  };
2447 
2448  bool noCwd = false;
2449  int debugLevel = 0;
2450  std::string networkStack;
2451  opterr = 0;
2452  int option = 0;
2453  while( (option = getopt_long( argc, argv, "+46d:h", options, 0 )) != -1 )
2454  {
2455  switch( option )
2456  {
2457  case '4':
2458  if( networkStack == "IPv6" )
2459  {
2460  std::cerr << "xrdfs: -4 and -6 are mutually exclusive" << std::endl;
2461  return 1;
2462  }
2463  networkStack = "IPv4";
2464  break;
2465  case '6':
2466  if( networkStack == "IPv4" )
2467  {
2468  std::cerr << "xrdfs: -4 and -6 are mutually exclusive" << std::endl;
2469  return 1;
2470  }
2471  networkStack = "IPv6";
2472  break;
2473  case 'd':
2474  {
2475  char *end = 0;
2476  long level = std::strtol( optarg, &end, 10 );
2477  if( !*optarg || *end || level < 0 || level > 3 )
2478  {
2479  std::cerr << "xrdfs: invalid debug level '" << optarg
2480  << "' (expected 0-3)" << std::endl;
2481  return 1;
2482  }
2483  debugLevel = static_cast<int>( level );
2484  break;
2485  }
2486  case 'h':
2487  PrintHelp( 0, 0, params );
2488  return 0;
2489  case NoCwdOption:
2490  noCwd = true;
2491  break;
2492  default:
2493  PrintHelp( 0, 0, params );
2494  return 1;
2495  }
2496  }
2497 
2498  if( !networkStack.empty() )
2499  DefaultEnv::GetEnv()->PutString( "NetworkStack", networkStack );
2500 
2501  if( debugLevel )
2502  {
2503  Log *log = DefaultEnv::GetLog();
2504  if( debugLevel == 1 )
2505  log->SetLevel( Log::InfoMsg );
2506  else if( debugLevel == 2 )
2507  log->SetLevel( Log::DebugMsg );
2508  else
2509  log->SetLevel( Log::DumpMsg );
2510  }
2511 
2512  if( optind == argc )
2513  {
2514  PrintHelp( 0, 0, params );
2515  return 1;
2516  }
2517 
2518  FSExecutor::CommandParams arguments( argv + optind, argv + argc );
2519  URL url;
2520  std::string error;
2521  URLCommandResult result = ParseURLCommand( arguments, url, error );
2522  if( result == InvalidURLCommand )
2523  {
2524  std::cerr << "xrdfs: " << error << std::endl;
2525  return 1;
2526  }
2527 
2528  if( result == ValidURLCommand )
2529  return ExecuteCommand( url, arguments );
2530 
2531  url = URL( arguments[0] );
2532  if( !url.IsValid() )
2533  {
2534  PrintHelp( 0, 0, params );
2535  return 1;
2536  }
2537 
2538  if( arguments.size() == 1 )
2539  return ExecuteInteractive( url, noCwd );
2540 
2541  arguments.erase( arguments.begin() );
2542 
2543  // Raw query parameters are implementation-dependent and may themselves look
2544  // like URLs, so query intentionally remains server-first only.
2545  if( arguments[0] != "query" )
2546  {
2547  URL inferredEndpoint;
2548  result = ParseURLCommand( arguments, inferredEndpoint, error );
2549  if( result == InvalidURLCommand )
2550  {
2551  std::cerr << "xrdfs: " << error << std::endl;
2552  return 1;
2553  }
2554 
2555  if( result == ValidURLCommand )
2556  {
2557  std::cerr << "xrdfs: cannot mix a leading endpoint with full URL "
2558  "operands; use either server-first or command-first syntax"
2559  << std::endl;
2560  return 1;
2561  }
2562  }
2563 
2564  return ExecuteCommand( url, arguments );
2565 }
@ kXR_fattrDel
Definition: XProtocol.hh:300
@ kXR_fattrSet
Definition: XProtocol.hh:303
@ kXR_fattrList
Definition: XProtocol.hh:302
@ kXR_fattrGet
Definition: XProtocol.hh:301
unsigned char kXR_char
Definition: XPtypes.hh:65
void PrintDirListStatInfo(StatInfo *info, bool hascks=false, uint32_t ownerwidth=0, uint32_t groupwidth=0, uint32_t sizewidth=0, bool human=false, uint64_t base=1000)
Definition: XrdClFS.cc:419
uint32_t nbDigits(uint64_t nb)
Definition: XrdClFS.cc:403
XRootDStatus DoQuery(FileSystem *fs, Env *env, const FSExecutor::CommandParams &args)
Definition: XrdClFS.cc:1346
XRootDStatus DoLocate(FileSystem *fs, Env *env, const FSExecutor::CommandParams &args)
Definition: XrdClFS.cc:958
int write_history(const char *)
Definition: XrdClFS.cc:2281
XRootDStatus DoMkDir(FileSystem *fs, Env *env, const FSExecutor::CommandParams &args)
Definition: XrdClFS.cc:647
void add_history(const char *)
Definition: XrdClFS.cc:2266
XRootDStatus DoRmDir(FileSystem *query, Env *env, const FSExecutor::CommandParams &args)
Definition: XrdClFS.cc:708
XRootDStatus DoRm(FileSystem *fs, Env *env, const FSExecutor::CommandParams &args)
Definition: XrdClFS.cc:795
XRootDStatus DoTail(FileSystem *fs, Env *env, const FSExecutor::CommandParams &args)
Definition: XrdClFS.cc:1717
int ExecuteInteractive(const URL &url, bool noCwd=false)
Definition: XrdClFS.cc:2364
int main(int argc, char **argv)
Definition: XrdClFS.cc:2435
void rl_bind_key(char, uint16_t)
Definition: XrdClFS.cc:2270
XRootDStatus DoStat(FileSystem *fs, Env *env, const FSExecutor::CommandParams &args)
Definition: XrdClFS.cc:1152
XRootDStatus ProcessStatQuery(StatInfo &info, const std::string &query)
Definition: XrdClFS.cc:1087
XRootDStatus DoCat(FileSystem *fs, Env *env, const FSExecutor::CommandParams &args)
Definition: XrdClFS.cc:1604
XRootDStatus BuildPath(std::string &newPath, Env *env, const std::string &path, const char *op=nullptr)
Definition: XrdClFS.cc:164
std::string BuildPrompt(Env *env, const URL &url)
Definition: XrdClFS.cc:2290
XRootDStatus DoMv(FileSystem *fs, Env *env, const FSExecutor::CommandParams &args)
Definition: XrdClFS.cc:747
XRootDStatus DoPrepare(FileSystem *fs, Env *env, const FSExecutor::CommandParams &args)
Definition: XrdClFS.cc:1449
XRootDStatus DoChMod(FileSystem *fs, Env *env, const FSExecutor::CommandParams &args)
Definition: XrdClFS.cc:911
XRootDStatus DoLS(FileSystem *fs, Env *env, const FSExecutor::CommandParams &args)
Definition: XrdClFS.cc:473
bool getArguments(std::vector< std::string > &result, const std::string &input)
Definition: XrdClFS.cc:2306
XRootDStatus DoCD(FileSystem *fs, Env *env, const FSExecutor::CommandParams &args)
Definition: XrdClFS.cc:354
XRootDStatus DoXAttr(FileSystem *fs, Env *env, const FSExecutor::CommandParams &args)
Definition: XrdClFS.cc:1887
XRootDStatus DoStatVFS(FileSystem *fs, Env *env, const FSExecutor::CommandParams &args)
Definition: XrdClFS.cc:1286
XRootDStatus DoCache(FileSystem *fs, Env *env, const FSExecutor::CommandParams &args)
Definition: XrdClFS.cc:294
XRootDStatus DoSpaceInfo(FileSystem *fs, Env *env, const FSExecutor::CommandParams &args)
Definition: XrdClFS.cc:1844
FSExecutor * CreateExecutor(const URL &url)
Definition: XrdClFS.cc:2209
int read_history(const char *)
Definition: XrdClFS.cc:2276
char * readline(const char *prompt)
Definition: XrdClFS.cc:2251
XRootDStatus ConvertMode(Access::Mode &mode, const std::string &modeStr)
Definition: XrdClFS.cc:249
int ExecuteCommand(FSExecutor *ex, const FSExecutor::CommandParams &args)
Definition: XrdClFS.cc:2239
uint16_t rl_insert
Definition: XrdClFS.cc:2274
std::string getSizeStr(uint64_t size, bool human, uint64_t base)
Definition: XrdClFS.cc:409
XRootDStatus DoTruncate(FileSystem *fs, Env *env, const FSExecutor::CommandParams &args)
Definition: XrdClFS.cc:864
XRootDStatus PrintHelp(FileSystem *, Env *, const FSExecutor::CommandParams &)
Definition: XrdClFS.cc:2049
int optind
static bool is_subdirectory(const std::string_view dir, const std::string_view subdir)
#define write(a, b, c)
Definition: XrdPosix.hh:121
void getline(uchar *buff, int blen)
const char * XrdSysE2T(int errcode)
Definition: XrdSysE2T.cc:104
virtual void EndJob(uint32_t jobNum, const XrdCl::PropertyList *results)
Definition: XrdClFS.cc:1564
virtual void JobProgress(uint32_t jobNum, uint64_t bytesProcessed, uint64_t bytesTotal)
Definition: XrdClFS.cc:1573
Binary blob representation.
Definition: XrdClBuffer.hh:34
void FromString(const std::string str)
Fill the buffer from a string.
Definition: XrdClBuffer.hh:205
std::string ToString() const
Convert the buffer to a string.
Definition: XrdClBuffer.hh:215
Copy the data from one point to another.
XRootDStatus Run(CopyProgressHandler *handler)
Run the copy jobs.
XRootDStatus Prepare()
XRootDStatus AddJob(const PropertyList &properties, PropertyList *results)
Interface for copy progress notification.
static Log * GetLog()
Get default log.
static Env * GetEnv()
Get default client environment.
DirList::iterator Iterator
Directory listing iterator.
Iterator End()
Get the end iterator.
Iterator Begin()
Get the begin iterator.
const std::string & GetParentName() const
Get parent directory name.
bool PutInt(const std::string &key, int value)
Definition: XrdClEnv.cc:136
bool PutString(const std::string &key, const std::string &value)
Definition: XrdClEnv.cc:52
bool GetString(const std::string &key, std::string &value)
Definition: XrdClEnv.cc:31
bool GetInt(const std::string &key, int &value)
Definition: XrdClEnv.cc:115
Execute queries given as a commandline.
std::vector< std::string > CommandParams
Definition of command argument list.
Env * GetEnv()
Get the environment.
XRootDStatus Execute(const CommandParams &args)
bool AddCommand(const std::string &name, Command command)
Container for space information.
uint64_t GetUsed() const
Amount of used space in MB.
uint64_t GetLargestFreeChunk() const
Largest single chunk of free space.
uint64_t GetTotal() const
Amount of total space in MB.
uint64_t GetFree() const
Amount of free space in MB.
static XRootDStatus GetSpaceInfo(SpaceInfo *&result, FileSystem *fs, const std::string &path)
Recursively get space information for given path.
Send file/filesystem queries to an XRootD cluster.
XRootDStatus Mv(const std::string &source, const std::string &dest, ResponseHandler *handler, time_t timeout=0) XRD_WARN_UNUSED_RESULT
XRootDStatus DirList(const std::string &path, DirListFlags::Flags flags, ResponseHandler *handler, time_t timeout=0) XRD_WARN_UNUSED_RESULT
XRootDStatus Locate(const std::string &path, OpenFlags::Flags flags, ResponseHandler *handler, time_t timeout=0) XRD_WARN_UNUSED_RESULT
XRootDStatus SendCache(const std::string &info, ResponseHandler *handler, time_t timeout=0) XRD_WARN_UNUSED_RESULT
XRootDStatus Truncate(const std::string &path, uint64_t size, ResponseHandler *handler, time_t timeout=0) XRD_WARN_UNUSED_RESULT
XRootDStatus RmDir(const std::string &path, ResponseHandler *handler, time_t timeout=0) XRD_WARN_UNUSED_RESULT
XRootDStatus ListXAttr(const std::string &path, ResponseHandler *handler, time_t timeout=0)
XRootDStatus Stat(const std::string &path, ResponseHandler *handler, time_t timeout=0) XRD_WARN_UNUSED_RESULT
XRootDStatus StatVFS(const std::string &path, ResponseHandler *handler, time_t timeout=0) XRD_WARN_UNUSED_RESULT
XRootDStatus GetXAttr(const std::string &path, const std::vector< std::string > &attrs, ResponseHandler *handler, time_t timeout=0)
XRootDStatus ChMod(const std::string &path, Access::Mode mode, ResponseHandler *handler, time_t timeout=0) XRD_WARN_UNUSED_RESULT
XRootDStatus DelXAttr(const std::string &path, const std::vector< std::string > &attrs, ResponseHandler *handler, time_t timeout=0)
XRootDStatus Prepare(const std::vector< std::string > &fileList, PrepareFlags::Flags flags, uint8_t priority, ResponseHandler *handler, time_t timeout=0) XRD_WARN_UNUSED_RESULT
XRootDStatus MkDir(const std::string &path, MkDirFlags::Flags flags, Access::Mode mode, ResponseHandler *handler, time_t timeout=0) XRD_WARN_UNUSED_RESULT
XRootDStatus Query(QueryCode::Code queryCode, const Buffer &arg, ResponseHandler *handler, time_t timeout=0) XRD_WARN_UNUSED_RESULT
XRootDStatus SetXAttr(const std::string &path, const std::vector< xattr_t > &attrs, ResponseHandler *handler, time_t timeout=0)
bool GetProperty(const std::string &name, std::string &value) const
XRootDStatus DeepLocate(const std::string &path, OpenFlags::Flags flags, ResponseHandler *handler, time_t timeout=0) XRD_WARN_UNUSED_RESULT
A file.
Definition: XrdClFile.hh:52
XRootDStatus Open(const std::string &url, OpenFlags::Flags flags, Access::Mode mode, ResponseHandler *handler, time_t timeout=0) XRD_WARN_UNUSED_RESULT
Definition: XrdClFile.cc:125
XRootDStatus Read(uint64_t offset, uint32_t size, void *buffer, ResponseHandler *handler, time_t timeout=0) XRD_WARN_UNUSED_RESULT
Definition: XrdClFile.cc:265
XRootDStatus Close(ResponseHandler *handler, time_t timeout=0) XRD_WARN_UNUSED_RESULT
Definition: XrdClFile.cc:210
XRootDStatus Stat(bool force, ResponseHandler *handler, time_t timeout=0) XRD_WARN_UNUSED_RESULT
Definition: XrdClFile.cc:236
Path location info.
Iterator Begin()
Get the location begin iterator.
@ Read
read access is allowed
@ ReadWrite
write access is allowed
@ ServerPending
server node where the file is pending to be online
@ ManagerOnline
manager node where the file is online
@ ServerOnline
server node where the file is online
@ ManagerPending
manager node where the file is pending to be online
LocationList::iterator Iterator
Iterator over locations.
Iterator End()
Get the location end iterator.
Handle diagnostics.
Definition: XrdClLog.hh:101
@ InfoMsg
print info
Definition: XrdClLog.hh:111
@ DebugMsg
print debug info
Definition: XrdClLog.hh:112
@ DumpMsg
print details of the request and responses
Definition: XrdClLog.hh:113
void SetLevel(LogLevel level)
Set the level of the messages that should be sent to the destination.
Definition: XrdClLog.hh:193
void Error(uint64_t topic, const char *format,...)
Report an error.
Definition: XrdClLog.cc:231
void Debug(uint64_t topic, const char *format,...)
Print a debug message.
Definition: XrdClLog.cc:282
Pipeline exception, wrapps an XRootDStatus.
const XRootDStatus & GetError() const
A key-value pair map storing both keys and values as strings.
uint64_t GetFreeRW() const
Get size of the largest contiguous area of free r/w space (in MB)
uint64_t GetNodesStaging() const
Get number of nodes that can provide staging space.
uint8_t GetUtilizationStaging() const
Get percentage of the partition utilization represented by FreeStaging.
uint64_t GetFreeStaging() const
Get size of the largest contiguous area of free staging space (in MB)
uint8_t GetUtilizationRW() const
Get percentage of the partition utilization represented by FreeRW.
uint64_t GetNodesRW() const
Get number of nodes that can provide read/write space.
Object stat info.
std::string GetChangeTimeAsString() const
Get change time.
std::string GetModTimeAsString() const
Get modification time.
bool HasChecksum() const
Has checksum.
bool TestFlags(uint32_t flags) const
Test flags.
uint64_t GetSize() const
Get size (in bytes)
const std::string GetModeAsOctString() const
Get mode.
const std::string & GetOwner() const
Get owner.
@ IsReadable
Read access is allowed.
@ IsDir
This is a directory.
@ Other
Neither a file nor a directory.
@ BackUpExists
Back up copy exists.
@ XBitSet
Executable/searchable bit set.
@ Offline
File is not online (ie. on disk)
@ IsWritable
Write access is allowed.
uint32_t GetFlags() const
Get flags.
bool ExtendedFormat() const
Has extended stat information.
const std::string & GetModeAsString() const
Get mode.
const std::string & GetId() const
Get id.
const std::string & GetGroup() const
Get group.
std::string GetAccessTimeAsString() const
Get change time.
const std::string & GetChecksum() const
Get checksum.
URL representation.
Definition: XrdClURL.hh:31
std::string GetHostId() const
Get the host part of the URL (user:password@host:port)
Definition: XrdClURL.hh:99
std::map< std::string, std::string > ParamsMap
Definition: XrdClURL.hh:33
const std::string & GetProtocol() const
Get the protocol.
Definition: XrdClURL.hh:118
void SetParams(const std::string &params)
Set params.
Definition: XrdClURL.cc:378
std::string GetURL() const
Get the URL.
Definition: XrdClURL.hh:86
std::string GetObfuscatedURL() const
Get the URL with authz information obfuscated.
Definition: XrdClURL.cc:474
void SetPath(const std::string &path)
Set the path.
Definition: XrdClURL.hh:225
bool IsValid() const
Is the url valid.
Definition: XrdClURL.cc:428
static void splitString(Container &result, const std::string &input, const std::string &delimiter)
Split a string.
Definition: XrdClUtils.hh:56
static std::string BytesToString(uint64_t bytes)
Convert bytes to a human readable string.
Definition: XrdClUtils.cc:367
std::string ToStr() const
Convert to string.
static std::string genHumanSize(size_t size, uint64_t base)
Definition: XrdOucUtils.cc:462
const uint16_t suPartial
Definition: XrdClStatus.hh:41
const uint16_t errInvalidAddr
Definition: XrdClStatus.hh:71
RmImpl< false > Rm
const uint16_t stError
An error occurred that could potentially be retried.
Definition: XrdClStatus.hh:32
const uint64_t AppMsg
const uint16_t errResponseNegative
Query response was negative.
Definition: XrdClStatus.hh:109
StatImpl< false > Stat(Ctx< File > file, Arg< bool > force, time_t timeout=0)
std::future< XRootDStatus > Async(Pipeline pipeline, time_t timeout=0)
ParallelOperation< false > Parallel(Container &&container)
Factory function for creating parallel operation from a vector.
const uint16_t errInvalidArgs
Definition: XrdClStatus.hh:58
XRootDStatus WaitFor(Pipeline pipeline, time_t timeout=0)
Mode
Access mode.
@ OX
world executable/browsable
@ OW
world writeable
@ UR
owner readable
@ GR
group readable
@ UW
owner writable
@ GX
group executable/browsable
@ GW
group writable
@ UX
owner executable/browsable
@ OR
world readable
@ Stat
Stat each entry.
@ Merge
Merge duplicates.
@ Zip
List content of ZIP files.
@ Recursive
Do a recursive listing.
@ Cksm
Get checksum for every entry.
@ None
Nothing special.
@ MakePath
create the entire directory tree if it doesn't exist
Flags
Open flags, may be or'd when appropriate.
@ Read
Open only for reading.
@ Cancel
cancel staging request
@ Colocate
co-locate staged files, if possible
Code
XRootD query request codes.
@ OpaqueFile
Implementation dependent.
@ XAttr
Query file extended attributes.
@ Opaque
Implementation dependent.
@ Config
Query server configuration.
@ Stats
Query server stats.
@ ChecksumCancel
Query file checksum cancellation.
@ Checksum
Query file checksum.
@ Space
Query logical space stats.
@ Prepare
Query prepare status.
uint16_t code
Error type, or additional hints on what to do.
Definition: XrdClStatus.hh:147
bool IsOK() const
We're fine.
Definition: XrdClStatus.hh:124
int GetShellCode() const
Get the status code that may be returned to the shell.
Definition: XrdClStatus.hh:129
Extended attribute operation status.
Extended attributes with status.