1 /*****************************************************************************/
2 /* Software Testing Automation Framework (STAF) */
3 /* (C) Copyright IBM Corp. 2001, 2004, 2005 */
4 /* */
5 /* This software is licensed under the Eclipse Public License (EPL) V1.0. */
6 /*****************************************************************************/
7
8 #include "STAF.h"
9 #include "STAF_iostream.h"
10 #include "STAF_fstream.h"
11 #include "STAFProc.h"
12 #include "STAFProcUtil.h"
13 #include "STAFString.h"
14 #include "STAFRefPtr.h"
15 #include "STAFUtil.h"
16 #include "STAFFSService.h"
17 #include "STAFConnectionManager.h"
18 #include "STAFVariablePool.h"
19 #include "STAFException.h"
20 #include "STAFFileSystem.h"
21 #include "STAFHandleManager.h"
22 #include "STAFFSCopyManager.h"
23 #include "STAFTrace.h"
24 #include "STAFConverter.h"
25 #include "STAFThreadManager.h"
26 #include "STAFDataTypes.h"
27 #include <set>
28 #include <cstring>
29 #include <deque>
30 #include <algorithm>
31
32 #ifdef STAF_USE_SSL
33 #include <openssl/evp.h>
34 #include <openssl/crypto.h>
35 #endif
36
37 typedef std::set<STAFString> SET_STAFString;
38 typedef std::deque<STAFFSEntryPtr> STAFFSEntryList;
39
40 static STAFMutexSem sStrictFSCopyTrustSem;
41 static const STAFString sEnabled = "Enabled";
42 static const STAFString sDisabled = "Disabled";
43 static const unsigned int sMaxReadAttempts = 20;
44 static const unsigned int sReadRetryDelay = 500; // 1/2 second (500ms)
45 static const STAFString sPeriod(kUTF8_PERIOD);
46 static const STAFString sDoublePeriod(sPeriod + sPeriod);
47 static const STAFString sNoneString("<None>");
48 static const STAFString sStar(kUTF8_STAR);
49 static const STAFString sDoubleQuote(kUTF8_DQUOTE);
50 static const STAFString sSpace(kUTF8_SPACE);
51 static STAFString sHelpMsg;
52
53 // Line ending strings for Windows and Unix
54 static const STAFString sWindowsEOL = STAFString(kUTF8_CR) +
55 STAFString(kUTF8_LF);
56 static const STAFString sUnixEOL = STAFString(kUTF8_LF);
57
58 // Maximum buffer size for searching for a line ending in a file
59 static const int sLineEndingBufferSize = 4000;
60
61 static STAFMapClassDefinitionPtr fListLongInfoClass;
62 static STAFMapClassDefinitionPtr fListDetailsInfoClass;
63 static STAFMapClassDefinitionPtr fListSummaryInfoClass;
64
65 // This table allows for lookup of a hex character (in UTF-8)
66 static const char HEX_TABLE[] =
67 {
68 // Here's the corresponding non-UTF-8 hex representation
69 // '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
70 // 'A', 'B', 'C', 'D', 'E', 'F'
71
72 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
73 0x41, 0x42, 0x43, 0x44, 0x45, 0x46
74 };
75
76 #ifdef STAF_USE_SSL
77 // The OpenSSL FAQ says: "Multi-threaded applications must provide two
78 // callback functions to OpenSSL by calling CRYPTO_set_locking_callback()
79 // and CRYPTO_set_id_callback(). Since the FS service's GET ENTRY CHECKSUM
80 // request calls OpenSSL apis, the FS service must provide these OpenSSL
81 // callback functions.
82
83 // This is a pointer to an array of mutexes needed by the OpenSSL locking
84 // callback function
85 #ifdef STAF_OS_TYPE_WIN32
86 static HANDLE *lock_cs;
87 #else
88 static pthread_mutex_t *lock_cs;
89 #endif
90
91 /*
92 * The locking callback function is needed to perform locking on shared data
93 * structures used by OpenSSL whenever multiple threads use OpenSSL.
94 * This function must be able to handle up to CRYPTO_num_locks() different
95 * mutex locks. It sets the n-th lock if mode & CRYPTO_LOCK, and releases it
96 * otherwise. We define one locking callback function for Windows and another
97 * for Unix operating systems.
98 */
99 #ifdef STAF_OS_TYPE_WIN32
STAF_SSL_Locking_Callback(int mode,int type,const char * file,int line)100 static void STAF_SSL_Locking_Callback(int mode, int type,
101 const char *file, int line)
102 {
103 if (mode & CRYPTO_LOCK)
104 WaitForSingleObject(lock_cs[type], INFINITE);
105 else
106 ReleaseMutex(lock_cs[type]);
107 }
108
109 #else
STAF_SSL_Locking_Callback(int mode,int type,const char * file,int line)110 static void STAF_SSL_Locking_Callback(int mode, int type,
111 const char *file, int line)
112 {
113 if (mode & CRYPTO_LOCK)
114 pthread_mutex_lock(&(lock_cs[type]));
115 else
116 pthread_mutex_unlock(&(lock_cs[type]));
117 }
118
119 /*
120 * This callback function returns a thread ID. It isn't needed on Windows
121 * nor on platforms where getpid() returns a different ID for each thread.
122 */
STAF_SSL_ThreadID_Callback()123 static unsigned long STAF_SSL_ThreadID_Callback()
124 {
125 return (unsigned long)pthread_self();
126 }
127 #endif
128
129 /*
130 * This function assigns the callback functions needed for multi-threaded
131 * applications that use OpenSSL so that they don't randomly crash.
132 */
STAF_SSL_Thread_Setup()133 static void STAF_SSL_Thread_Setup()
134 {
135 // The CRYPTO_set_locking_callback() method requires an array of mutexes
136 // that is needed for locking access to global shared data structure
137 // used by OpenSSL
138
139 # ifdef STAF_OS_TYPE_WIN32
140 lock_cs = (HANDLE *)OPENSSL_malloc(
141 CRYPTO_num_locks() * sizeof(HANDLE));
142 # else
143 lock_cs = (pthread_mutex_t *)OPENSSL_malloc(
144 CRYPTO_num_locks() * sizeof(pthread_mutex_t));
145 # endif
146
147 for (int i = 0; i < CRYPTO_num_locks(); i++)
148 {
149 # ifdef STAF_OS_TYPE_WIN32
150 lock_cs[i] = CreateMutex(NULL, FALSE, NULL);
151 # else
152 pthread_mutex_init(&(lock_cs[i]), NULL);
153 # endif
154 }
155
156 // Assign callback functions needed for multi-threaded applications
157 // that use OpenSSL
158
159 CRYPTO_set_locking_callback(STAF_SSL_Locking_Callback);
160
161 // If Unix, assign a callback function for returning a thread id
162
163 # ifndef STAF_OS_TYPE_WIN32
164 CRYPTO_set_id_callback(STAF_SSL_ThreadID_Callback);
165 # endif
166 }
167
STAF_SSL_Thread_Cleanup()168 static void STAF_SSL_Thread_Cleanup()
169 {
170 // Remove the SSL locking callback function
171
172 CRYPTO_set_locking_callback(NULL);
173
174 // If Unix, Remove the SSL thread id callback function
175
176 # ifndef STAF_OS_TYPE_WIN32
177 CRYPTO_set_id_callback(NULL);
178 # endif
179
180 // Delete the mutexes used for locking by OpenSSL
181
182 for (int i = 0; i < CRYPTO_num_locks(); i++)
183 {
184 # ifdef STAF_OS_TYPE_WIN32
185 CloseHandle(lock_cs[i]);
186 # else
187 pthread_mutex_destroy(&(lock_cs[i]));
188 # endif
189 }
190
191 OPENSSL_free(lock_cs);
192 }
193 #endif
194
195 struct STAFSortEnumByName
196 {
STAFSortEnumByNameSTAFSortEnumByName197 STAFSortEnumByName(STAFFSCaseSensitive_t caseSensitive)
198 : fCaseSensitive(caseSensitive)
199 { /* Do nothing */ }
200
operator ()STAFSortEnumByName201 bool operator()(STAFFSEntryPtr lhs, STAFFSEntryPtr rhs)
202 {
203 unsigned int comp = 0;
204
205 if (fCaseSensitive == kSTAFFSCaseSensitive)
206 {
207 STAFStringCompareTo(lhs->path().asString().getImpl(),
208 rhs->path().asString().getImpl(), &comp, 0);
209 }
210 else
211 {
212 STAFStringCompareTo(lhs->path().asString().toUpperCase().getImpl(),
213 rhs->path().asString().toUpperCase().getImpl(),
214 &comp, 0);
215 }
216
217 return (comp == 1);
218 }
219
220 STAFFSCaseSensitive_t fCaseSensitive;
221 };
222
223
sortEnumBySize(STAFFSEntryPtr lhs,STAFFSEntryPtr rhs)224 static bool sortEnumBySize(STAFFSEntryPtr lhs, STAFFSEntryPtr rhs)
225 {
226 return (lhs->size64() < rhs->size64());
227 }
228
229
sortEnumByModTime(STAFFSEntryPtr lhs,STAFFSEntryPtr rhs)230 static bool sortEnumByModTime(STAFFSEntryPtr lhs, STAFFSEntryPtr rhs)
231 {
232 return (lhs->modTime() < rhs->modTime());
233 }
234
235
getTypeString(STAFFSEntryType_t type)236 STAFString getTypeString(STAFFSEntryType_t type)
237 {
238 switch (type)
239 {
240 case kSTAFFSFile: return "F";
241 case kSTAFFSSpecialDirectory: // Fall through
242 case kSTAFFSDirectory: return "D";
243 case kSTAFFSPipe: return "P";
244 case kSTAFFSSocket: return "S";
245 case kSTAFFSSymLink: return "L";
246 case kSTAFFSBlkDev: return "B";
247 case kSTAFFSCharDev: return "C";
248 case kSTAFFSOther: return "O";
249 default: return "?";
250 }
251 }
252
getTypeMaskFromString(const STAFString & typeString,bool includeSpecial)253 unsigned int getTypeMaskFromString(const STAFString &typeString,
254 bool includeSpecial)
255 {
256 STAFString upperTypeString = typeString.toUpperCase();
257 unsigned int entryTypesUInt = kSTAFFSNone;
258
259 for (int i = 0; i < upperTypeString.length(STAFString::kChar); ++i)
260 {
261 STAFString thisChar = upperTypeString.subString(i, 1, STAFString::kChar);
262
263 if ((thisChar == "!") && includeSpecial)
264 {
265 entryTypesUInt |= kSTAFFSSpecialDirectory;
266 }
267 else if (thisChar == "F") entryTypesUInt |= kSTAFFSFile;
268 else if (thisChar == "D") entryTypesUInt |= kSTAFFSDirectory;
269 else if (thisChar == "P") entryTypesUInt |= kSTAFFSPipe;
270 else if (thisChar == "S") entryTypesUInt |= kSTAFFSSocket;
271 else if (thisChar == "L") entryTypesUInt |= kSTAFFSSymLink;
272 else if (thisChar == "B") entryTypesUInt |= kSTAFFSBlkDev;
273 else if (thisChar == "C") entryTypesUInt |= kSTAFFSCharDev;
274 else if (thisChar == "O") entryTypesUInt |= kSTAFFSOther;
275 }
276
277 return entryTypesUInt;
278 }
279
280
updateResultString(STAFObjectPtr & outputList,STAFFSEntryPtr & entry,STAFRC_t rc,unsigned int osRC)281 void updateResultString(STAFObjectPtr &outputList, STAFFSEntryPtr &entry,
282 STAFRC_t rc, unsigned int osRC)
283 {
284 if (rc != kSTAFOk)
285 {
286 STAFObjectPtr errorInfoMap = STAFObject::createMap();
287 errorInfoMap->put("staf-map-class-name",
288 "STAF/Service/FS/ErrorInfo");
289 errorInfoMap->put("name", entry->path().asString());
290 errorInfoMap->put("rc", STAFString(rc));
291
292 if (rc == kSTAFBaseOSError)
293 errorInfoMap->put("osRC", STAFString(osRC));
294
295 // Add remaining map entries here
296 outputList->append(errorInfoMap);
297 }
298 }
299
300
readFile(fstream & inFile,char * fileBuffer,unsigned int readLength,const STAFString fromFile,const STAFString toMachine,unsigned int fileLength,unsigned int currentPos)301 STAFRC_t readFile(fstream &inFile, char *fileBuffer, unsigned int readLength,
302 const STAFString fromFile, const STAFString toMachine,
303 unsigned int fileLength, unsigned int currentPos)
304 {
305 /* Leave in (commented out) for future debugging purposes.
306 // Make sure that currentPos is the correct current position in the file
307 // (indicating the number of bytes read so far) now that we're no longer
308 // using tellg() because it only returns an int which means it does not
309 // support files >= 2G.
310 if (currentPos <= (INT_MAX - readLength))
311 {
312 int currentPosInt = inFile.tellg();// Save current position before read
313 unsigned int myCurrentPos = (unsigned int)currentPosInt;
314
315 if (myCurrentPos != currentPos)
316 {
317 cout << "STAFFSService::readFile() - MISMATCH: myCurrentPos="
318 << myCurrentPos << " currentPos=" << currentPos << endl;
319 }
320 }
321 */
322
323 // Read a block of data from the file
324
325 inFile.read(fileBuffer, readLength);
326
327 if (inFile.good())
328 return kSTAFOk; // Read was successful
329
330 // If get eof condition reading the file, make sure that all bytes have
331 // really been read to make sure it's not a "pre-mature" eof condition.
332 //
333 // Note: A "pre-mature" eof condition can occur on Windows when copying
334 // from a file on a mapped drive (in text mode) and the drive is
335 // disconnected.
336
337 if (inFile.eof() && (currentPos + inFile.gcount() == fileLength))
338 return kSTAFOk; // Completed reading the file
339
340 // The read failed. Retry the read up to sMaxReadAttempts times with a
341 // delay between each attempt.
342
343 for (int readAttempt = 1;
344 !inFile.good() && readAttempt <= sMaxReadAttempts;
345 readAttempt++)
346 {
347 if (inFile.fail())
348 {
349 // Recoverable read error
350
351 // Log a warning tracepoint message
352
353 STAFString warningMsg(
354 "STAFFSService::readFile() - Read attempt #" +
355 STAFString(readAttempt) + " failed while copying file " +
356 fromFile + " to machine " + toMachine + " after reading " +
357 STAFString(currentPos) + " bytes");
358
359 STAFTrace::trace(kSTAFTraceWarning, warningMsg);
360
361 // Delay and retry read after clearing any error flags and
362 // repositioning the file pointer
363
364 STAFThreadManager::sleepCurrentThread(
365 sReadRetryDelay);
366
367 inFile.clear();
368
369 if (readAttempt == sMaxReadAttempts)
370 {
371 // Before the last read attempt, try closing the file and
372 // reopening it first to see if that fixes the problem
373
374 inFile.close();
375 inFile.open(fromFile.toCurrentCodePage()->buffer(),
376 ios::in | STAF_ios_binary);
377 }
378
379 if (currentPos <= INT_MAX)
380 {
381 inFile.seekg(currentPos, ios::beg);
382 inFile.read(fileBuffer, readLength);
383 }
384 else
385 {
386 // Reading a large file, so need to do multiple seekg()'s
387 // because seekg() only accepts an integer for the offset
388
389 inFile.seekg(INT_MAX, ios::beg);
390
391 unsigned int setPos = currentPos - INT_MAX;
392
393 while (setPos > INT_MAX)
394 {
395 inFile.seekg(INT_MAX, ios::cur);
396 setPos = setPos - INT_MAX;
397 }
398
399 inFile.seekg((int)setPos, ios::cur);
400
401 if (inFile.good())
402 inFile.read(fileBuffer, readLength);
403 }
404 }
405 else if (inFile.bad())
406 {
407 // Unrecoverable read error.
408 break;
409 }
410 }
411
412 if (!inFile.good())
413 {
414 // Unrecoverable read failure
415
416 return kSTAFFileReadError;
417 }
418
419 return kSTAFOk;
420 }
421
422
determineLineEnding(unsigned int fileLength,fstream & inFile,const STAFString & fromFile,const STAFString & toMachine,const STAFString & defaultEOL)423 STAFServiceResult determineLineEnding(unsigned int fileLength,
424 fstream &inFile,
425 const STAFString &fromFile,
426 const STAFString &toMachine,
427 const STAFString &defaultEOL)
428 {
429 // Determine current EOL (End Of Line ending) as follows:
430 // 1) Look for the first Windows line ending and the first Unix
431 // line ending in the first 4000 characters of the source file.
432 // Whichever line ending is found first will be assumed to be
433 // the line ending in this text file.
434 // 2) If no Windows or Unix line ending character is found in the
435 // first 4000 characters, then default to the line ending
436 // character for the type of operating system where the source
437 // source file resides.
438 //
439 // If successful, the current EOL will be returned in the fResult
440 // of the STAFServiceResult returned.
441
442 STAFString currentEOL = STAFString("");
443
444 if (fileLength > 0)
445 {
446 char *buffer = new char[sLineEndingBufferSize];
447 unsigned int readLength = STAF_MIN(sLineEndingBufferSize, fileLength);
448
449 STAFRC_t rc = readFile(inFile, buffer, readLength,
450 fromFile, toMachine, fileLength, 0);
451
452 if (rc == kSTAFOk)
453 {
454 // Create a STAFString containing up to the first 4000 bytes
455 // of the file data
456
457 try
458 {
459 STAFString fileData = STAFString(buffer, readLength);
460
461 // Check which line ending is found first in the file and
462 // assign to currentEOL
463
464 unsigned int windowsEOLIndex = fileData.find(sWindowsEOL);
465 unsigned int unixEOLIndex = fileData.find(sUnixEOL);
466
467 if (windowsEOLIndex < unixEOLIndex)
468 currentEOL = sWindowsEOL;
469 else if (unixEOLIndex < windowsEOLIndex)
470 currentEOL = sUnixEOL;
471 }
472 catch (...)
473 {
474 // Do nothing
475 }
476 }
477
478 // Set the file pointer back to the beginning of the file
479
480 inFile.clear();
481 inFile.seekg(0, ios::beg);
482 }
483
484 if (currentEOL.length() == 0)
485 {
486 // Could not determine the current EOL by looking for the first EOL in
487 // the first 4000 bytes, so set to source machine's OS line ending.
488
489 if (defaultEOL.length() > 0)
490 {
491 // On a directory copy, the line ending for the source machine
492 // has already been determined and is passed in as defaultEOL
493
494 currentEOL = defaultEOL;
495 }
496 else
497 {
498 STAFConfigInfo sysInfo;
499 STAFString_t errorBuffer;
500 unsigned int osRC;
501
502 if (STAFUtilGetConfigInfo(&sysInfo, &errorBuffer, &osRC) !=
503 kSTAFOk)
504 {
505 return STAFServiceResult(
506 kSTAFBaseOSError,
507 STAFString("Get current EOL failure. ") +
508 STAFString(errorBuffer, STAFString::kShallow) +
509 ", RC: " + osRC);
510 }
511
512 currentEOL = sysInfo.lineSeparator;
513 }
514 }
515
516 return STAFServiceResult(kSTAFOk, currentEOL);
517 }
518
copyDirectory(STAFFSEnumPtr childEnum,STAFString fromDir,STAFConnectionPtr connection,SET_STAFString textExtList,STAFString currentEOL,STAFString newEOL,bool doCodepageConvert,int level,STAFFSCaseSensitive_t caseSensitive,STAFObjectPtr & outputList,STAFFSCopyManager::FSCopyDataPtr copyDataPtr,const STAFString & toMachine)519 STAFRC_t copyDirectory(STAFFSEnumPtr childEnum, STAFString fromDir,
520 STAFConnectionPtr connection, SET_STAFString textExtList,
521 STAFString currentEOL, STAFString newEOL, bool doCodepageConvert,
522 int level, STAFFSCaseSensitive_t caseSensitive, STAFObjectPtr &outputList,
523 STAFFSCopyManager::FSCopyDataPtr copyDataPtr, const STAFString &toMachine)
524 {
525 unsigned int osRC = 0;
526 STAFRC_t rc = kSTAFOk;
527 STAFRC_t ack = kSTAFOk;
528 STAFString ackResult;
529 STAFFSEntryPtr fileEntry;
530 STAFString toFile;
531 bool textTransfer;
532 bool doConvert = doCodepageConvert;
533 SET_STAFString::iterator i;
534
535 for (; childEnum->isValid(); childEnum->next())
536 {
537 fileEntry = childEnum->entry();
538 STAFString fromFile = fileEntry->path().asString();
539 fromFile = fromFile.replace(kUTF8_BSLASH, kUTF8_SLASH);
540 toFile = fromFile.subString(fromDir.length());
541
542 // Open the file to copy
543
544 fstream inFile(fromFile.toCurrentCodePage()->buffer(),
545 ios::in | STAF_ios_binary);
546
547 if (!inFile)
548 {
549 updateResultString(outputList, fileEntry,
550 kSTAFFileOpenError, osRC);
551 continue;
552 }
553
554 // Get the size of the file (upperSize and lowerSize).
555 // If the file size is < 4G, upperSize will be zero.
556
557 unsigned int upperSize = fileEntry->size().first;
558 unsigned int lowerSize = fileEntry->size().second;
559
560 if (upperSize > 0)
561 {
562 // File size exceeds the maximum that the FS service handles
563
564 updateResultString(outputList, fileEntry,
565 kSTAFFileReadError, osRC);
566 // XXX: How provide a better error message such as the following?
567 //"File size exceeds maximum size ") + UINT_MAX + ") supported"
568
569 inFile.close();
570 continue;
571 }
572
573 unsigned int fileLength = lowerSize;
574
575 // Determine if this file is to be text or binary
576
577 textTransfer = false;
578 unsigned int isMatch;
579
580 for(i = textExtList.begin(); i != textExtList.end(); i++)
581 {
582 isMatch = STAFFileSystem::matchesWildcards(
583 fileEntry->path().extension(), *i, caseSensitive);
584 textTransfer |= (isMatch > 0);
585 }
586
587 if (textTransfer)
588 {
589 // Determine what line ending the from file contains
590
591 STAFServiceResult result = determineLineEnding(
592 fileLength, inFile, fromFile, toMachine, currentEOL);
593
594 if (result.fRC != kSTAFOk)
595 {
596 updateResultString(outputList, fileEntry, result.fRC, osRC);
597 // XXX: How provide a better error message such as
598 // result.fResult?
599
600 continue;
601 }
602
603 currentEOL = result.fResult;
604 }
605
606 doCodepageConvert = doConvert && textTransfer;
607
608 textTransfer &= (!newEOL.isEqualTo(currentEOL));
609
610 connection->writeUInt(kSTAFFSContinueCopy);
611
612 connection->writeUInt(kSTAFFSFile);
613 connection->writeString(toFile);
614
615 if (level > 1)
616 {
617 if (doCodepageConvert)
618 connection->writeUInt(kSTAFFSTextConvert);
619 else if (textTransfer)
620 connection->writeUInt(kSTAFFSTextNoConvert);
621 else
622 connection->writeUInt(kSTAFFSBinary);
623 }
624
625 char fileBuffer[4000] = {0};
626 unsigned int writeLength = 0;
627
628 STAFRC_t ack = static_cast<STAFRC_t>(connection->readUInt());
629 ackResult = connection->readString();
630
631 if (ack != kSTAFOk)
632 {
633 updateResultString(outputList, fileEntry, ack, osRC);
634 inFile.close();
635 continue;
636 }
637
638 if (doCodepageConvert)
639 {
640 // Perform a text transfer with conversion of eol chars and a
641 // codepage conversion. It runs considerably slower than the
642 // binary transfer. This is the type of transfer that will occur
643 // if the TEXTEXT option is specified and the codepages are
644 // different. Data is sent as a series of buffers of UTF8 chars.
645
646 gFSCopyManagerPtr->updateDirectoryCopy(
647 copyDataPtr, fromFile, kSTAFFSTextConvert, fileLength);
648
649 connection->writeString(currentEOL);
650
651 if (fileLength > 0)
652 {
653 STAFStringBufferPtr eolStr =
654 currentEOL.toCurrentCodePage();
655
656 // How many bytes in the end-of-line sequence
657 unsigned int eolBufferSize = eolStr->length();
658
659 // Points to a buffer containing end-of-line sequence
660 char *eolBuffer = new char[eolBufferSize];
661
662 try
663 {
664 memcpy(eolBuffer, eolStr->buffer(), eolBufferSize);
665
666 // Last byte of end-of-line sequence
667 char eolLastChar = eolBuffer[eolBufferSize - 1];
668
669 const unsigned int sBufferSize = 4096;
670
671 STAFRefPtr<char> buffer = STAFRefPtr<char>
672 (new char[sBufferSize], STAFRefPtr<char>::INIT,
673 STAFRefPtr<char>::ARRAY);
674
675 unsigned int bufferSize = sBufferSize;
676 unsigned int readOffset = 0; // Buffer read offset
677 unsigned int bytesCopied = 0;
678 bool done = false;
679
680 while (!done)
681 {
682 rc = readFile(inFile,
683 static_cast<char *>(buffer + readOffset),
684 bufferSize - readOffset,
685 fromFile, toMachine,
686 fileLength, bytesCopied);
687
688 if (rc != kSTAFOk)
689 {
690 updateResultString(outputList, fileEntry,
691 rc, osRC);
692 break;
693 }
694
695 unsigned int bytesInBuffer = inFile.gcount() +
696 readOffset;
697
698 bytesCopied += inFile.gcount();
699
700 if (bytesInBuffer < bufferSize) done = true;
701
702 // Find a newline. Make sure we don't underrun the
703 // buffer.
704
705 unsigned int i = 0;
706 unsigned int guardIndex = eolBufferSize - 1;
707
708 if (bytesInBuffer > 0)
709 {
710 i = bytesInBuffer - 1; // Last NewLine index
711
712 while (((buffer[i] != eolLastChar) ||
713 !memcmp(buffer + i - eolBufferSize,
714 eolBuffer, eolBufferSize)) &&
715 (i > guardIndex))
716 { --i; }
717 }
718
719 while ((i == guardIndex) && !done)
720 {
721 // We have a line bigger than our buffer.
722 // Note: the beginning of the buffer may be a lone
723 // newline, but we ignore that for this algorithm
724 // (as the next line is likely larger than the
725 // buffer anyway.
726
727 // First, create a buffer that is double our
728 // current size, and copy our existing buffer data
729 // into it.
730
731 STAFRefPtr<char> tmpBuffer = STAFRefPtr<char>
732 (new char[bufferSize * 2],
733 STAFRefPtr<char>::INIT,
734 STAFRefPtr<char>::ARRAY);
735
736 memcpy(tmpBuffer, buffer, bufferSize);
737 buffer = tmpBuffer;
738 bufferSize *= 2;
739
740 // Now, read in data to fill remainder of the
741 // buffer
742
743 rc = readFile(inFile, buffer + (bufferSize / 2),
744 bufferSize / 2, fromFile, toMachine,
745 fileLength, bytesCopied);
746
747 if (rc != kSTAFOk)
748 {
749 updateResultString(outputList, fileEntry,
750 rc, osRC);
751 break;
752 }
753
754 bytesInBuffer += inFile.gcount();
755 bytesCopied += inFile.gcount();
756
757 // Finally, let's check to make sure that this
758 // buffer was big enough, by finding a newline.
759 // Otherwise, let's run the loop again.
760
761 if (bytesInBuffer < bufferSize) done = true;
762
763 i = 0;
764
765 if (bytesInBuffer > 0)
766 {
767 i = bytesInBuffer - 1; // Last NewLine index
768 guardIndex = (bufferSize / 2) - eolBufferSize;
769
770 while (((buffer[i] != eolLastChar) ||
771 !memcmp(buffer + i - eolBufferSize,
772 eolBuffer, eolBufferSize)) &&
773 (i > guardIndex))
774 { --i; }
775 }
776 } // while ((i == guardIndex) && !done)
777
778 // We now have the last newline in the buffer
779
780 if (!done)
781 {
782 // Need to see if can create a STAFString (e.g.
783 // without getting a codepage converter exception,
784 // before writing kSTAFFSContinueCopy and the data
785
786 STAFString data = STAFString(
787 buffer, i + 1, STAFString::kCurrent);
788
789 connection->writeUInt(kSTAFFSContinueCopy);
790 connection->writeString(data);
791
792 memmove(buffer, buffer + i + 1,
793 bufferSize - i - 1);
794
795 readOffset = bufferSize - i - 1;
796 }
797 else
798 {
799 // Need to see if can create a STAFString (e.g.
800 // without getting a codepage converter exception,
801 // before writing kSTAFFSContinueCopy and the data
802
803 STAFString data = STAFString(
804 buffer, bytesInBuffer, STAFString::kCurrent);
805
806 connection->writeUInt(kSTAFFSContinueCopy);
807 connection->writeString(data);
808 }
809
810 gFSCopyManagerPtr->updateFileCopy(copyDataPtr,
811 bytesCopied);
812 } // while (!done)
813 }
814 catch (STAFException &e)
815 {
816 // XXX: It would be nice if we could provide more
817 // information on the error using e.getText().
818
819 rc = e.getErrorCode();
820 updateResultString(outputList, fileEntry, rc, osRC);
821 }
822
823 delete[] eolBuffer;
824
825 } // if (fileLength > 0)
826
827 connection->writeUInt(kSTAFFSFinishedCopy);
828
829 inFile.close();
830
831 if (rc == kSTAFOk)
832 {
833 // Read an ack, so that we know the file is closed
834
835 ack = connection->readUInt();
836
837 if (ack != kSTAFOk)
838 {
839 updateResultString(outputList, fileEntry, ack, osRC);
840 }
841 }
842 }
843
844 /* This if clause is used to perform a text transfer with
845 conversion of eol chars without a codepage conversion
846 It runs considerably faster than the codepage conversion
847 transfer.
848 This is the type of transfer that will occur if the NOCONVERT
849 option is enabled
850 This is the type of transfer that will occur if the codepages
851 are the same and a text transfer has been specified
852 */
853 else if (textTransfer)
854 {
855 gFSCopyManagerPtr->updateDirectoryCopy(
856 copyDataPtr, fromFile, kSTAFFSTextNoConvert, fileLength);
857
858 STAFString transferString;
859 int bufferSize = 3000;
860 unsigned int transferLen = 0;
861 char *buffer = new char[bufferSize];
862 unsigned int bytesCopied = 0;
863
864 connection->writeString(currentEOL);
865 connection->writeUInt(bufferSize);
866
867 while ((fileLength > 0) && (inFile.good()))
868 {
869 transferLen = STAF_MIN(bufferSize, fileLength);
870
871 rc = readFile(inFile, buffer, transferLen, fromFile,
872 toMachine, fileLength, bytesCopied);
873
874 if (rc != kSTAFOk)
875 {
876 updateResultString(outputList, fileEntry, rc, osRC);
877 fileLength = 0;
878 break;
879 }
880
881 connection->writeUInt(transferLen);
882 connection->write(buffer, transferLen);
883
884 fileLength -= transferLen;
885 bytesCopied += transferLen;
886 gFSCopyManagerPtr->updateFileCopy(copyDataPtr, bytesCopied);
887 }
888
889 connection->writeUInt(kSTAFFSFinishedCopy);
890
891 delete[] buffer;
892 inFile.close();
893
894 if (rc == kSTAFOk)
895 {
896 // Read an ack, so that we know the file is closed
897
898 ack = connection->readUInt();
899
900 if (ack != kSTAFOk)
901 {
902 updateResultString(outputList, fileEntry, ack, osRC);
903 fileLength = 0;
904 }
905 }
906 }
907 else
908 {
909 // Perform a binary transfer of a file
910
911 unsigned int bytesCopied = 0;
912
913 gFSCopyManagerPtr->updateDirectoryCopy(
914 copyDataPtr, fromFile, kSTAFFSBinary, fileLength);
915
916 connection->writeUInt(fileLength);
917
918 if (level > 3)
919 {
920 // Starting with level 4 for the STAFDirectoryCopyAPI, to
921 // improve performance, acks are no longer sent/received
922 // after each read/write. Instead, a final ack is received
923 // after the entire file is processed which indicates if
924 // the copy was successful.
925
926 while ((fileLength > 0) && (inFile.good()))
927 {
928 writeLength = STAF_MIN(sizeof(fileBuffer), fileLength);
929
930 rc = readFile(
931 inFile, reinterpret_cast<char *>(fileBuffer),
932 writeLength, fromFile, toMachine, fileLength,
933 bytesCopied);
934
935 if (rc != kSTAFOk) break;
936
937 connection->write(fileBuffer, writeLength);
938 fileLength -= writeLength;
939 bytesCopied += writeLength;
940 gFSCopyManagerPtr->updateFileCopy(
941 copyDataPtr, bytesCopied);
942 }
943
944 inFile.close();
945
946 if (rc == kSTAFOk)
947 {
948 // Receive the final acknowledgement that indicates if
949 // the file was copied successfully
950 rc = connection->readUInt();
951 }
952
953 if (rc != kSTAFOk)
954 {
955 // Update error information in result
956 updateResultString(outputList, fileEntry, rc, osRC);
957 fileLength = 0;
958 }
959 }
960 else
961 {
962 // Levels < 4 for the STAFDirectoryCopyAPI send/receive
963 // acknowledgements after each read/write.
964
965 while ((fileLength > 0) && (inFile.good()))
966 {
967 writeLength = STAF_MIN(sizeof(fileBuffer), fileLength);
968
969 rc = readFile(
970 inFile, reinterpret_cast<char *>(fileBuffer),
971 writeLength, fromFile, toMachine, fileLength,
972 bytesCopied);
973
974 if (rc != kSTAFOk)
975 {
976 updateResultString(outputList, fileEntry, rc, osRC);
977 fileLength = 0;
978 connection->writeUInt(kSTAFFileReadError);
979 break;
980 }
981
982 connection->writeUInt(kSTAFOk);
983 connection->write(fileBuffer, writeLength);
984 fileLength -= writeLength;
985
986 ack = connection->readUInt();
987
988 if (ack != kSTAFOk)
989 {
990 updateResultString(outputList, fileEntry, ack, osRC);
991 fileLength = 0;
992 break;
993 }
994
995 bytesCopied += writeLength;
996 gFSCopyManagerPtr->updateFileCopy(
997 copyDataPtr, bytesCopied);
998 }
999
1000 inFile.close();
1001 }
1002 }
1003 }
1004
1005 return kSTAFOk;
1006 }
1007
1008
recurseCopyDir(STAFFSEntryPtr entry,const STAFString & namePattern,const STAFString & extPattern,STAFString fromDir,bool keepEmptyDir,bool onlyDir,unsigned int entryTypesUInt,STAFConnectionPtr connection,STAFFSCaseSensitive_t caseSensitive,SET_STAFString textExtList,STAFString currentEOL,STAFString newEOL,int level,bool doCodepageConvert,STAFObjectPtr & outputList,STAFFSCopyManager::FSCopyDataPtr copyDataPtr,const STAFString & toMachine)1009 STAFRC_t recurseCopyDir(STAFFSEntryPtr entry, const STAFString &namePattern,
1010 const STAFString &extPattern, STAFString fromDir, bool keepEmptyDir,
1011 bool onlyDir, unsigned int entryTypesUInt, STAFConnectionPtr connection,
1012 STAFFSCaseSensitive_t caseSensitive, SET_STAFString textExtList ,
1013 STAFString currentEOL, STAFString newEOL, int level, bool doCodepageConvert,
1014 STAFObjectPtr &outputList, STAFFSCopyManager::FSCopyDataPtr copyDataPtr,
1015 const STAFString &toMachine)
1016 {
1017 unsigned int osRC = 0;
1018 STAFRC_t rc = kSTAFOk;
1019
1020 // Enumerate the files in the current entry
1021 STAFFSEnumPtr fileEnum = entry->enumerate(namePattern, extPattern,
1022 STAFFSEntryType_t(entryTypesUInt & ~kSTAFFSDirectory),
1023 kSTAFFSNoSort, caseSensitive);
1024
1025 STAFString thisDir = entry->path().asString();
1026
1027 // relative toDirectory
1028 STAFString toDir = thisDir.subString(fromDir.length());
1029 toDir = toDir.replace(kUTF8_BSLASH, kUTF8_SLASH);
1030
1031 // If the thisDir is equal to fromDir, then the directory already exists
1032 // If there is at least one file to be copied or KEEPEMPTYDIRECTORIES
1033 // or ONLYDIRECTORIES option was used, then create the current directory.
1034 if ((thisDir != fromDir) &&
1035 (onlyDir || keepEmptyDir || (fileEnum->isValid())))
1036 {
1037 connection->writeUInt(kSTAFFSContinueCopy);
1038 connection->writeUInt(kSTAFFSDirectory);
1039 connection->writeString(toDir);
1040
1041 //...wait for STAFProc's ack
1042 STAFRC_t ack = static_cast<STAFRC_t>(connection->readUInt());
1043 STAFString ackResult = connection->readString();
1044
1045 if (ack != kSTAFOk)
1046 updateResultString(outputList, entry, ack, osRC);
1047 }
1048
1049 // copy current directory
1050 if (!onlyDir && fileEnum->isValid())
1051 copyDirectory(fileEnum, fromDir, connection, textExtList, currentEOL,
1052 newEOL, doCodepageConvert, level, caseSensitive,
1053 outputList, copyDataPtr, toMachine);
1054
1055 // Enumerate the directories in the current entry
1056 STAFFSEnumPtr directoryEnum = entry->enumerate(kUTF8_STAR, kUTF8_STAR,
1057 STAFFSEntryType_t(entryTypesUInt & ~kSTAFFSFile),
1058 kSTAFFSNoSort, caseSensitive);
1059
1060 // copy sub-directories in current directory
1061 for (; directoryEnum->isValid(); directoryEnum->next())
1062 {
1063 recurseCopyDir(directoryEnum->entry(), namePattern, extPattern,
1064 fromDir, keepEmptyDir, onlyDir, entryTypesUInt,
1065 connection, caseSensitive, textExtList, currentEOL,
1066 newEOL, level, doCodepageConvert, outputList,
1067 copyDataPtr, toMachine);
1068 }
1069
1070 return kSTAFOk;
1071 }
1072
1073
removeChildren(STAFFSEntryPtr entry,const STAFString & namePattern,const STAFString & extPattern,unsigned int entryTypesUInt,STAFFSCaseSensitive_t caseSensitive,STAFObjectPtr & outputList)1074 STAFRC_t removeChildren(STAFFSEntryPtr entry, const STAFString &namePattern,
1075 const STAFString &extPattern,
1076 unsigned int entryTypesUInt,
1077 STAFFSCaseSensitive_t caseSensitive, STAFObjectPtr &outputList)
1078 {
1079 STAFFSEnumPtr childEnum = entry->enumerate(namePattern, extPattern,
1080 STAFFSEntryType_t(entryTypesUInt),
1081 kSTAFFSNoSort, caseSensitive);
1082 unsigned int osRC = 0;
1083 STAFRC_t rc = kSTAFOk;
1084
1085 for (; childEnum->isValid(); childEnum->next())
1086 {
1087 STAFFSEntryPtr entry = childEnum->entry();
1088 rc = entry->remove(&osRC);
1089 updateResultString(outputList, entry, rc, osRC);
1090 }
1091
1092 return kSTAFOk;
1093 }
1094
1095
recurseRemove(STAFFSEntryPtr entry,const STAFString & namePattern,const STAFString & extPattern,unsigned int entryTypesUInt,STAFFSCaseSensitive_t caseSensitive,STAFObjectPtr & outputList)1096 STAFRC_t recurseRemove(STAFFSEntryPtr entry, const STAFString &namePattern,
1097 const STAFString &extPattern, unsigned int entryTypesUInt,
1098 STAFFSCaseSensitive_t caseSensitive, STAFObjectPtr &outputList)
1099 {
1100 STAFFSEnumPtr childDirEnum = entry->enumerate(kUTF8_STAR, kUTF8_STAR,
1101 kSTAFFSDirectory);
1102 STAFRC_t rc = kSTAFOk;
1103
1104 for (; childDirEnum->isValid(); childDirEnum->next())
1105 {
1106 STAFFSEntryPtr childDirEntry = childDirEnum->entry();
1107
1108 // If child directory entry is a link, skip it
1109
1110 if (!childDirEntry->isLink())
1111 {
1112 rc = recurseRemove(childDirEntry, namePattern, extPattern,
1113 entryTypesUInt, caseSensitive, outputList);
1114 }
1115 }
1116
1117 rc = removeChildren(entry, namePattern, extPattern, entryTypesUInt,
1118 caseSensitive, outputList);
1119
1120 return kSTAFOk;
1121 }
1122
1123
addListDirectoryEntry(STAFString rootDir,STAFFSEntryPtr entry,STAFObjectPtr & outputList,STAFObjectPtr & mc,bool showLong,bool details)1124 STAFRC_t addListDirectoryEntry(
1125 STAFString rootDir, STAFFSEntryPtr entry, STAFObjectPtr &outputList,
1126 STAFObjectPtr &mc, bool showLong, bool details)
1127 {
1128 // Remove the root directory from the name
1129
1130 STAFString theName = entry->path().asString();
1131 theName = theName.subString(rootDir.length() + 1);
1132
1133 // Adds an entry in the specified format to the outputList.
1134 // Used when listing the contents of a directory..
1135
1136 if (showLong && details)
1137 {
1138 STAFObjectPtr fileInfoMap = fListDetailsInfoClass->createInstance();
1139 fileInfoMap->put("name", theName);
1140 fileInfoMap->put("type", getTypeString(entry->type()));
1141 fileInfoMap->put("size", STAFString(entry->size64()));
1142 fileInfoMap->put("upperSize", STAFString(entry->size().first));
1143 fileInfoMap->put("lowerSize", STAFString(entry->size().second));
1144 fileInfoMap->put("lastModifiedTimestamp",
1145 entry->modTime().asString());
1146
1147 if (entry->linkTarget() != "")
1148 fileInfoMap->put("linkTarget", entry->linkTarget());
1149
1150 outputList->append(fileInfoMap);
1151 }
1152 else if (showLong && !details)
1153 {
1154 STAFObjectPtr fileInfoMap = fListLongInfoClass->createInstance();
1155 fileInfoMap->put("type", getTypeString(entry->type()));
1156
1157 STAFString sizeInfo;
1158 STAFUInt64_t size = entry->size64();
1159
1160 if (size > (99999 * 1024))
1161 sizeInfo = STAFString(size / (1024 * 1024)) + "M"; // Megabytes
1162 else if (size > 99999)
1163 sizeInfo = STAFString(size / 1024) + "K"; // Kilobytes
1164 else
1165 sizeInfo = STAFString(size); // Bytes
1166
1167 fileInfoMap->put("size", sizeInfo);
1168
1169 fileInfoMap->put("lastModifiedTimestamp", entry->modTime().asString());
1170 fileInfoMap->put("name", theName);
1171
1172 if (entry->linkTarget() != "")
1173 fileInfoMap->put("linkTarget", entry->linkTarget());
1174
1175 outputList->append(fileInfoMap);
1176 }
1177 else
1178 {
1179 outputList->append(theName);
1180 }
1181
1182 return kSTAFOk;
1183 }
1184
1185
1186 /*****************************************************************************/
1187 /* getDirectorySize - Gets the total size of the entries in a directory */
1188 /* whose name, extension, type, and case-sensitivity */
1189 /* match the specified criteria. If the recurse argument */
1190 /* is true, the size will also include the sizes of the */
1191 /* entries in subdirectories that match the specified */
1192 /* criteria. */
1193 /* */
1194 /* Accepts: (In) File system entry (must be for a directory) */
1195 /* (In) Name pattern (* indicates to match the name of any entry */
1196 /* in the directory) */
1197 /* (In) Extension pattern (* indicates to match the extension of */
1198 /* any entry in the directory) */
1199 /* (In) Types (types of entries in the directory that match) */
1200 /* (In) Case sensitive (indicates whether to match the name and */
1201 /* extension patterns in a case sensitive manner) */
1202 /* (In) Recurse (true indicates to count matching entries in */
1203 /* subdirectories) */
1204 /* (Out) Total size of the directory */
1205 /* (Out) Number of files in the directory */
1206 /* (Out) Number of subdirectories in the directory */
1207 /* */
1208 /* Returns: Standard return codes */
1209 /*****************************************************************************/
getDirectorySize(const STAFFSEntryPtr dirEntry,const STAFString & namePattern,const STAFString & extPattern,const unsigned int entryTypesUInt,const STAFFSCaseSensitive_t caseSensitive,const bool recurse,STAFUInt64_t & size,STAFUInt64_t & numFiles,STAFUInt64_t & numDirectories)1210 STAFRC_t getDirectorySize(const STAFFSEntryPtr dirEntry,
1211 const STAFString &namePattern,
1212 const STAFString &extPattern,
1213 const unsigned int entryTypesUInt,
1214 const STAFFSCaseSensitive_t caseSensitive,
1215 const bool recurse,
1216 STAFUInt64_t &size, STAFUInt64_t &numFiles,
1217 STAFUInt64_t &numDirectories)
1218 {
1219 // Enumerate all entries in the directory with the specified types,
1220 // and also all sub-directories if the recurse option was specified
1221
1222 STAFFSEntryType_t entryTypes;
1223
1224 if (recurse)
1225 entryTypes = STAFFSEntryType_t(entryTypesUInt | kSTAFFSDirectory);
1226 else
1227 entryTypes = STAFFSEntryType_t(entryTypesUInt);
1228
1229 // Get an enumeration of the entries (specify no sorting since only
1230 // getting a summary)
1231
1232 STAFFSEnumPtr dirEnum = dirEntry->enumerate(
1233 kUTF8_STAR, kUTF8_STAR, entryTypes, kSTAFFSNoSort, caseSensitive);
1234
1235 // Iterate through the entries
1236
1237 for (; dirEnum->isValid(); dirEnum->next())
1238 {
1239 STAFFSEntryPtr entry = dirEnum->entry();
1240
1241 // Check if name and extension (in the specified case) and type
1242 // match the specified criteria
1243
1244 if ((STAFFileSystem::matchesWildcards(entry->path().name(),
1245 namePattern, caseSensitive)) &&
1246 (STAFFileSystem::matchesWildcards(entry->path().extension(),
1247 extPattern, caseSensitive)) &&
1248 (entry->type() & STAFFSEntryType_t(entryTypesUInt)))
1249 {
1250 // This entry matches the specified criteria
1251
1252 if (!entry->isLink())
1253 {
1254 // If the entry is a link, the size is for the entry it is
1255 // linked to (which may not even be in the same directory)
1256 // so don't include the size of a link entry
1257
1258 size += entry->size64();
1259 }
1260
1261 if (entry->type() & kSTAFFSDirectory)
1262 numDirectories++;
1263 else
1264 numFiles++;
1265 }
1266
1267 // If recurse was specified and the entry is a directory, get the total
1268 // size of the directory
1269
1270 if (recurse && (entry->type() & kSTAFFSDirectory))
1271 {
1272 // Skip special directories . and ..
1273
1274 if ((entry->path().name() == sPeriod) ||
1275 (entry->path().name() == sDoublePeriod))
1276 continue;
1277
1278 getDirectorySize(
1279 entry, namePattern, extPattern, entryTypesUInt, caseSensitive,
1280 recurse, size, numFiles, numDirectories);
1281 }
1282 }
1283
1284 return kSTAFOk;
1285 }
1286
1287
recurseListDir(STAFFSEntryPtr dirEntry,const STAFString & namePattern,const STAFString & extPattern,unsigned int entryTypesUInt,STAFFSCaseSensitive_t caseSensitive,STAFFSSortBy_t sortBy,STAFFSEntryList & entryList)1288 STAFRC_t recurseListDir(
1289 STAFFSEntryPtr dirEntry, const STAFString &namePattern,
1290 const STAFString &extPattern, unsigned int entryTypesUInt,
1291 STAFFSCaseSensitive_t caseSensitive, STAFFSSortBy_t sortBy,
1292 STAFFSEntryList &entryList)
1293 {
1294 // Enumerate all entries whose type matches one specified, as well as
1295 // enumerate all directory entries
1296
1297 STAFFSEnumPtr dirEnum = dirEntry->enumerate(
1298 kUTF8_STAR, kUTF8_STAR,
1299 STAFFSEntryType_t(STAFFSEntryType_t(entryTypesUInt) |
1300 kSTAFFSDirectory),
1301 sortBy, caseSensitive);
1302
1303 // Iterate through all the entriess
1304
1305 for (; dirEnum->isValid(); dirEnum->next())
1306 {
1307 STAFFSEntryPtr entry = dirEnum->entry();
1308
1309 // Check if name and extension (in the specifies case) and type
1310 // match the specified criteria
1311
1312 if ((STAFFileSystem::matchesWildcards(entry->path().name(),
1313 namePattern, caseSensitive)) &&
1314 (STAFFileSystem::matchesWildcards(entry->path().extension(),
1315 extPattern, caseSensitive)) &&
1316 (entry->type() & STAFFSEntryType_t(entryTypesUInt)))
1317 {
1318 // This entries matches the specified criteria so add an entry
1319 // to the matching entry list
1320
1321 entryList.push_back(entry);
1322 }
1323
1324 // Check if entry is a directory, recursively check if any of it's
1325 // entries match the specified criteria
1326
1327 if (entry->type() & kSTAFFSDirectory)
1328 {
1329 // Skip special directories . and ..
1330
1331 if ((entry->path().name() == sPeriod) ||
1332 (entry->path().name() == sDoublePeriod))
1333 continue;
1334
1335 recurseListDir(entry, namePattern, extPattern, entryTypesUInt,
1336 caseSensitive, sortBy, entryList);
1337 }
1338 }
1339
1340 return kSTAFOk;
1341 }
1342
1343
convertToHex(const char * buffer,unsigned int fileLength)1344 STAFServiceResult convertToHex(const char *buffer,
1345 unsigned int fileLength)
1346 {
1347 // Convert the buffer to a hex format
1348
1349 STAFBuffer<char> hexBuffer(new char[fileLength * 2],
1350 STAFBuffer<char>::INIT,
1351 STAFBuffer<char>::ARRAY);
1352
1353 for (unsigned int i = 0, j = 0; i < fileLength; i++)
1354 {
1355 hexBuffer[j++] = HEX_TABLE[(buffer[i] >> 4) & 0xF];
1356 hexBuffer[j++] = HEX_TABLE[buffer[i] & 0xF];
1357 }
1358
1359 // Return new result in hex format
1360 return STAFServiceResult(kSTAFOk, STAFString(hexBuffer, fileLength * 2,
1361 STAFString::kUTF8));
1362 }
1363
1364
convertLineEndings(const char * buffer,unsigned int fileLength,const STAFString & textFormat,const STAFString & orgMachine,bool isLocalRequest,bool testFlag)1365 STAFServiceResult convertLineEndings(const char *buffer,
1366 unsigned int fileLength,
1367 const STAFString &textFormat,
1368 const STAFString &orgMachine,
1369 bool isLocalRequest,
1370 bool testFlag)
1371 {
1372 // Convert the line ending characters in the buffer
1373
1374 // Determine the new line ending character(s) to use
1375
1376 STAFString newEOL = STAFString("");
1377
1378 if (textFormat.toUpperCase() == "NATIVE")
1379 {
1380 if (!isLocalRequest)
1381 {
1382 // Try to get the line separator for the originating machine.
1383 // If VAR resolve request fails (probably due to insufficient
1384 // trust), default to target system's line separator.
1385
1386 // XXX: In STAF V3.x, change to get the line separator from
1387 // information passed to the service.
1388
1389 STAFResultPtr lineSepResult = gSTAFProcHandlePtr->submit(
1390 orgMachine, "VAR", "RESOLVE STRING " +
1391 STAFHandle::wrapData("{STAF/Config/Sep/Line}"));
1392
1393 if (lineSepResult->rc == kSTAFOk)
1394 {
1395 // XXX: If the originating machine is running STAF v2.x,
1396 // using the new VAR resolve string syntax does not
1397 // return a 7 due to the parser assuming the rest of
1398 // the string should be the value, so it line separator
1399 // begins with "STRING " (which is NOT what we want).
1400 if (lineSepResult->result.find("STRING ") != 0)
1401 newEOL = lineSepResult->result;
1402 else
1403 {
1404 // Try using the old VAR resolve syntax in case the
1405 // originating machine is running STAF v2.x.
1406 lineSepResult = gSTAFProcHandlePtr->submit(
1407 orgMachine, "VAR", "RESOLVE " +
1408 STAFHandle::wrapData("{STAF/Config/Sep/Line}"));
1409
1410 if (lineSepResult->rc == kSTAFOk)
1411 newEOL = lineSepResult->result;
1412 }
1413 }
1414 }
1415
1416 if (newEOL == STAFString(""))
1417 {
1418 // Get the line ending character(s) for the system where the
1419 // file resides.
1420
1421 STAFConfigInfo configInfo;
1422 STAFString_t errorBufferT;
1423 unsigned int osRC = 0;
1424
1425 if (STAFUtilGetConfigInfo(&configInfo, &errorBufferT, &osRC)
1426 != kSTAFOk)
1427 {
1428 return STAFServiceResult(
1429 kSTAFBaseOSError,
1430 STAFString(errorBufferT, STAFString::kShallow) +
1431 ", RC: " + osRC);
1432 }
1433
1434 // Default to the target system's line separator if target
1435 // system is the same as the orginating system (e.g. is local) or
1436 // if can't get the originating system's line separator.
1437
1438 newEOL = configInfo.lineSeparator;
1439 }
1440 }
1441 else if (textFormat.toUpperCase() == "WINDOWS")
1442 newEOL = sWindowsEOL;
1443 else if (textFormat.toUpperCase() == "UNIX")
1444 newEOL = sUnixEOL;
1445 else
1446 newEOL = textFormat;
1447
1448 // Create a STAFString containing the file data
1449
1450 STAFString result = "";
1451
1452 try
1453 {
1454 result = STAFString(buffer, fileLength);
1455 }
1456 catch (STAFException &e)
1457 {
1458 result = e.getText();
1459
1460 if (e.getErrorCode() == kSTAFConverterError)
1461 {
1462 result += ": The file contains data that is not valid in the "
1463 "codepage that STAF is using. To see the codepage that STAF "
1464 "is using, check the value of STAF variable "
1465 "STAF/Config/CodePage.";
1466 }
1467
1468 return STAFServiceResult(e.getErrorCode(), result);
1469 }
1470 catch (...)
1471 {
1472 result = "Caught unknown exception in STAFFSService::"
1473 "convertLineEndings() when trying to create a STAFString from "
1474 "the data in the file";
1475 return STAFServiceResult(kSTAFUnknownError, result);
1476 }
1477
1478 // Check which line endings the file actually contains and assign
1479 // to currentEOL. The first line-ending found for Windows (0D0A)
1480 // or Unix (0A) determines the line endings assumed for the file.
1481 // If no line-endings are found in the file, default to newEOL
1482 // so that no line-endings conversion is done.
1483
1484 STAFString currentEOL = newEOL;
1485
1486 unsigned int windowsEOLIndex = result.find(sWindowsEOL);
1487 unsigned int unixEOLIndex = result.find(sUnixEOL);
1488
1489 if (windowsEOLIndex < unixEOLIndex)
1490 currentEOL = sWindowsEOL;
1491 else if (unixEOLIndex < windowsEOLIndex)
1492 currentEOL = sUnixEOL;
1493
1494 // If debug flag is true, prints line ending characters in hex
1495
1496 bool debug = false;
1497
1498 if (debug)
1499 {
1500 cout << "currentEOL in Hex: ";
1501
1502 const char *buffer = currentEOL.buffer();
1503
1504 for (unsigned int y = 0; y < currentEOL.length(); ++y)
1505 {
1506 unsigned int currChar = static_cast<unsigned char>(buffer[y]);
1507 if (currChar < 16) cout << "0";
1508 cout << hex << currChar << dec << " ";
1509 }
1510
1511 cout << endl << "newEOL in Hex: ";
1512
1513 buffer = newEOL.buffer();
1514
1515 for (unsigned int i = 0; i < newEOL.length(); ++i)
1516 {
1517 unsigned int currChar = static_cast<unsigned char>(buffer[i]);
1518 if (currChar < 16) cout << "0";
1519 cout << hex << currChar << dec << " ";
1520 }
1521
1522 cout << endl << endl;
1523 }
1524
1525 // If conversion of line ending character(s) is needed, replace the
1526 // current line ending character(s) with the new line ending character(s)
1527
1528 if (currentEOL != newEOL)
1529 result = result.replace(currentEOL, newEOL);
1530
1531 // If testFlag, convert the result to hex to verify that the line-ending
1532 // characters were converted as expected.
1533
1534 if (testFlag)
1535 return convertToHex(result.buffer(), result.length());
1536
1537 // Return new result in hex format
1538 return STAFServiceResult(kSTAFOk, result);
1539 }
1540
1541
STAFFSService()1542 STAFFSService::STAFFSService() : STAFService("FS")
1543 {
1544 // Assign the help text string for the service
1545
1546 sHelpMsg = STAFString("*** FS Service Help ***") +
1547 *gLineSeparatorPtr + *gLineSeparatorPtr +
1548 "COPY FILE <Name> [TOFILE <Name> | TODIRECTORY <Name>] "
1549 "[TOMACHINE <Machine>]" +
1550 *gLineSeparatorPtr +
1551 " [TEXT [FORMAT <Format>]] [FAILIFEXISTS | FAILIFNEW]" +
1552 //Remove comment when enabling convert/noconvert option
1553 //" [CONVERT | NOCONVERT]]" +
1554 *gLineSeparatorPtr + *gLineSeparatorPtr +
1555 "COPY DIRECTORY <Name> [TODIRECTORY <Name>] [TOMACHINE <Machine>]" +
1556 *gLineSeparatorPtr +
1557 " [NAME <Pattern>] [EXT <Pattern>] "
1558 "[CASESENSITIVE | CASEINSENSITIVE]" +
1559 *gLineSeparatorPtr +
1560 " [TEXTEXT <Pattern>... [FORMAT <Format>]] " +
1561 // Remove comment when enabling convert/noconvert option
1562 //"[CONVERT | NOCONVERT]]" +
1563 *gLineSeparatorPtr +
1564 " [RECURSE [KEEPEMPTYDIRECTORIES | ONLYDIRECTORIES]]" +
1565 *gLineSeparatorPtr +
1566 " [IGNOREERRORS] [FAILIFEXISTS | FAILIFNEW]" +
1567 *gLineSeparatorPtr + *gLineSeparatorPtr +
1568 "MOVE FILE <Name> <TOFILE <Name> | TODIRECTORY <Name>>" +
1569 *gLineSeparatorPtr + *gLineSeparatorPtr +
1570 "MOVE DIRECTORY <Name> TODIRECTORY <Name>" +
1571 *gLineSeparatorPtr + *gLineSeparatorPtr +
1572 "GET FILE <Name> [[TEXT | BINARY] [FORMAT <Format>]]" +
1573 *gLineSeparatorPtr + *gLineSeparatorPtr +
1574 "GET ENTRY <Name> <TYPE | SIZE | MODTIME | LINKTARGET" +
1575 #ifdef STAF_USE_SSL
1576 " | " +
1577 *gLineSeparatorPtr +
1578 " CHECKSUM [<Algorithm>]" +
1579 #endif
1580 ">" +
1581 *gLineSeparatorPtr +
1582 "QUERY ENTRY <Name>" +
1583 *gLineSeparatorPtr + *gLineSeparatorPtr +
1584 "CREATE DIRECTORY <Name> [FULLPATH] [FAILIFEXISTS]" +
1585 *gLineSeparatorPtr + *gLineSeparatorPtr +
1586 "LIST DIRECTORY <Name> [RECURSE] [LONG [DETAILS] | SUMMARY] "
1587 "[TYPE <Types>]" +
1588 *gLineSeparatorPtr +
1589 " [NAME <Pattern>] [EXT <Pattern>] "
1590 "[CASESENSITIVE | CASEINSENSITIVE]" +
1591 *gLineSeparatorPtr +
1592 " [SORTBYNAME | SORTBYSIZE | SORTBYMODTIME]" +
1593 *gLineSeparatorPtr + *gLineSeparatorPtr +
1594 "LIST COPYREQUESTS [LONG] [INBOUND] [OUTBOUND]" +
1595 *gLineSeparatorPtr +
1596 " [FILE [[BINARY] [TEXT]]] [DIRECTORY]" +
1597 *gLineSeparatorPtr + *gLineSeparatorPtr +
1598 "LIST SETTINGS" + *gLineSeparatorPtr + *gLineSeparatorPtr +
1599 "DELETE ENTRY <Name> CONFIRM [RECURSE] [IGNOREERRORS]" +
1600 *gLineSeparatorPtr +
1601 " [ CHILDREN [TYPE <Types>] [NAME <Pattern>] [EXT <Pattern>]" +
1602 *gLineSeparatorPtr +
1603 " [CASESENSITIVE | CASEINSENSITIVE] ]" +
1604 *gLineSeparatorPtr + *gLineSeparatorPtr +
1605 "SET STRICTFSCOPYTRUST <Enabled | Disabled>" +
1606 *gLineSeparatorPtr + *gLineSeparatorPtr +
1607 "HELP";
1608
1609 // Create the command request parsers
1610
1611 // COPY FILE parser setup
1612
1613 fCopyFileParser.addOption("COPY", 1,
1614 STAFCommandParser::kValueNotAllowed);
1615 fCopyFileParser.addOption("FILE", 1,
1616 STAFCommandParser::kValueRequired);
1617 fCopyFileParser.addOption("TOFILE", 1,
1618 STAFCommandParser::kValueRequired);
1619 fCopyFileParser.addOption("TODIRECTORY", 1,
1620 STAFCommandParser::kValueRequired);
1621 fCopyFileParser.addOption("TOMACHINE", 1,
1622 STAFCommandParser::kValueRequired);
1623 fCopyFileParser.addOption("FORMAT", 1,
1624 STAFCommandParser::kValueRequired);
1625 fCopyFileParser.addOption("TEXT", 1,
1626 STAFCommandParser::kValueNotAllowed);
1627 // Remove comment when enabling convert/noconvert option
1628 /*fCopyFileParser.addOption("CONVERT", 1,
1629 STAFCommandParser::kValueNotAllowed);
1630 fCopyFileParser.addOption("NOCONVERT", 1,
1631 STAFCommandParser::kValueNotAllowed);*/
1632 fCopyFileParser.addOption("FAILIFEXISTS", 1,
1633 STAFCommandParser::kValueNotAllowed);
1634 fCopyFileParser.addOption("FAILIFNEW", 1,
1635 STAFCommandParser::kValueNotAllowed);
1636
1637 fCopyFileParser.addOptionGroup("FAILIFEXISTS FAILIFNEW", 0, 1);
1638 fCopyFileParser.addOptionGroup("TOFILE TODIRECTORY", 0, 1);
1639
1640 // Remove comment when enabling convert/noconvert option
1641 //fCopyFileParser.addOptionGroup("CONVERT NOCONVERT", 0, 1);
1642
1643 fCopyFileParser.addOptionNeed("FORMAT", "TEXT");
1644
1645 // Remove comment when enabling convert/noconvert option
1646 //fCopyFileParser.addOptionNeed("CONVERT", "TEXT");
1647 //fCopyFileParser.addOptionNeed("NOCONVERT", "TEXT");
1648 fCopyFileParser.addOptionNeed("COPY", "FILE");
1649
1650 // COPY DIRECTORY parser setup
1651
1652 fCopyDirParser.addOption("COPY", 1,
1653 STAFCommandParser::kValueNotAllowed);
1654 fCopyDirParser.addOption("DIRECTORY", 1,
1655 STAFCommandParser::kValueRequired);
1656 fCopyDirParser.addOption("TODIRECTORY", 1,
1657 STAFCommandParser::kValueRequired);
1658 fCopyDirParser.addOption("TOMACHINE", 1,
1659 STAFCommandParser::kValueRequired);
1660 fCopyDirParser.addOption("NAME", 1,
1661 STAFCommandParser::kValueRequired);
1662 fCopyDirParser.addOption("EXT", 1,
1663 STAFCommandParser::kValueRequired);
1664 fCopyDirParser.addOption("TEXTEXT", 0,
1665 STAFCommandParser::kValueRequired);
1666 fCopyDirParser.addOption("FORMAT", 1,
1667 STAFCommandParser::kValueRequired);
1668 // Remove comment when enabling convert/noconvert option
1669 /*fCopyDirParser.addOption("CONVERT", 1,
1670 STAFCommandParser::kValueNotAllowed);
1671 fCopyDirParser.addOption("NOCONVERT", 1,
1672 STAFCommandParser::kValueNotAllowed);*/
1673 fCopyDirParser.addOption("RECURSE", 1,
1674 STAFCommandParser::kValueNotAllowed);
1675 fCopyDirParser.addOption("CASESENSITIVE", 1,
1676 STAFCommandParser::kValueNotAllowed);
1677 fCopyDirParser.addOption("CASEINSENSITIVE", 1,
1678 STAFCommandParser::kValueNotAllowed);
1679 fCopyDirParser.addOption("KEEPEMPTYDIRECTORIES", 1,
1680 STAFCommandParser::kValueNotAllowed);
1681 fCopyDirParser.addOption("ONLYDIRECTORIES", 1,
1682 STAFCommandParser::kValueNotAllowed);
1683 fCopyDirParser.addOption("IGNOREERRORS", 1,
1684 STAFCommandParser::kValueNotAllowed);
1685 fCopyDirParser.addOption("FAILIFEXISTS", 1,
1686 STAFCommandParser::kValueNotAllowed);
1687 fCopyDirParser.addOption("FAILIFNEW", 1,
1688 STAFCommandParser::kValueNotAllowed);
1689
1690 fCopyDirParser.addOptionGroup("CASESENSITIVE CASEINSENSITIVE", 0, 1);
1691 fCopyDirParser.addOptionGroup("KEEPEMPTYDIRECTORIES ONLYDIRECTORIES", 0, 1);
1692 fCopyDirParser.addOptionGroup("FAILIFEXISTS FAILIFNEW", 0, 1);
1693 // Remove comment when enabling convert/noconvert option
1694 //fCopyDirParser.addOptionGroup("CONVERT NOCONVERT", 0, 1);
1695
1696 fCopyDirParser.addOptionNeed("FORMAT", "TEXTEXT");
1697 // Remove comment when enabling convert/noconvert option
1698 //fCopyDirParser.addOptionNeed("CONVERT", "TEXTEXT");
1699 //fCopyDirParser.addOptionNeed("NOCONVERT", "TEXTEXT");
1700 fCopyDirParser.addOptionNeed("KEEPEMPTYDIRECTORIES ONLYDIRECTORIES",
1701 "RECURSE");
1702 fCopyDirParser.addOptionNeed("COPY", "DIRECTORY");
1703
1704 // MOVE FILE parser setup
1705
1706 fMoveFileParser.addOption("MOVE", 1, STAFCommandParser::kValueNotAllowed);
1707 fMoveFileParser.addOption("FILE", 1, STAFCommandParser::kValueRequired);
1708 fMoveFileParser.addOption("TOFILE", 1, STAFCommandParser::kValueRequired);
1709 fMoveFileParser.addOption("TODIRECTORY", 1, STAFCommandParser::kValueRequired);
1710 fMoveFileParser.addOptionGroup("TOFILE TODIRECTORY", 1, 1);
1711 fMoveFileParser.addOptionNeed("MOVE", "FILE");
1712
1713 // MOVE DIRECTORY parser setup
1714
1715 fMoveDirParser.addOption("MOVE", 1, STAFCommandParser::kValueNotAllowed);
1716 fMoveDirParser.addOption(
1717 "DIRECTORY", 1, STAFCommandParser::kValueRequired);
1718 fMoveDirParser.addOption(
1719 "TODIRECTORY", 1, STAFCommandParser::kValueRequired);
1720 fMoveDirParser.addOptionNeed("MOVE", "DIRECTORY");
1721 fMoveDirParser.addOptionNeed("DIRECTORY", "TODIRECTORY");
1722
1723 // GET parser setup
1724
1725 fGetParser.addOption("GET", 1,
1726 STAFCommandParser::kValueNotAllowed);
1727 fGetParser.addOption("FILE", 1,
1728 STAFCommandParser::kValueRequired);
1729
1730 fGetParser.addOption("TEXT", 1,
1731 STAFCommandParser::kValueNotAllowed);
1732 fGetParser.addOption("BINARY", 1,
1733 STAFCommandParser::kValueNotAllowed);
1734 fGetParser.addOption("FORMAT", 1,
1735 STAFCommandParser::kValueRequired);
1736
1737 // Note that TEST is an undocumented option that we can use for testing
1738 // that the line ending character really got converted correctly
1739 fGetParser.addOption("TEST", 1,
1740 STAFCommandParser::kValueNotAllowed);
1741
1742 fGetParser.addOption("ENTRY", 1,
1743 STAFCommandParser::kValueRequired);
1744 fGetParser.addOption("TYPE", 1,
1745 STAFCommandParser::kValueNotAllowed);
1746 fGetParser.addOption("SIZE", 1,
1747 STAFCommandParser::kValueNotAllowed);
1748 fGetParser.addOption("MODTIME", 1,
1749 STAFCommandParser::kValueNotAllowed);
1750 fGetParser.addOption("LINKTARGET", 1,
1751 STAFCommandParser::kValueNotAllowed);
1752 #ifdef STAF_USE_SSL
1753 fGetParser.addOption("CHECKSUM", 1,
1754 STAFCommandParser::kValueAllowed);
1755 #endif
1756
1757 fGetParser.addOptionGroup("FILE ENTRY", 1, 1);
1758
1759 fGetParser.addOptionGroup("TEXT BINARY", 0, 1);
1760 fGetParser.addOptionNeed("TEXT BINARY", "FILE");
1761 fGetParser.addOptionNeed("FORMAT", "TEXT BINARY");
1762 fGetParser.addOptionNeed("TEST", "FILE");
1763
1764 fGetParser.addOptionNeed("GET", "FILE ENTRY");
1765 #ifdef STAF_USE_SSL
1766 fGetParser.addOptionNeed("TYPE SIZE MODTIME LINKTARGET CHECKSUM", "ENTRY");
1767 fGetParser.addOptionNeed("ENTRY", "TYPE SIZE MODTIME LINKTARGET CHECKSUM");
1768 #else
1769 fGetParser.addOptionNeed("TYPE SIZE MODTIME LINKTARGET", "ENTRY");
1770 fGetParser.addOptionNeed("ENTRY", "TYPE SIZE MODTIME LINKTARGET");
1771 #endif
1772
1773 // LIST parser setup
1774
1775 fListParser.addOption(
1776 "LIST", 1, STAFCommandParser::kValueNotAllowed);
1777 fListParser.addOption(
1778 "DIRECTORY", 1, STAFCommandParser::kValueRequired);
1779 fListParser.addOption(
1780 "NAME", 1, STAFCommandParser::kValueRequired);
1781 fListParser.addOption(
1782 "EXT", 1, STAFCommandParser::kValueRequired);
1783 fListParser.addOption(
1784 "LONG", 1, STAFCommandParser::kValueNotAllowed);
1785 fListParser.addOption(
1786 "DETAILS", 1, STAFCommandParser::kValueNotAllowed);
1787 fListParser.addOption(
1788 "SUMMARY", 1, STAFCommandParser::kValueNotAllowed);
1789 fListParser.addOption(
1790 "SORTBYNAME", 1, STAFCommandParser::kValueNotAllowed);
1791 fListParser.addOption(
1792 "SORTBYSIZE", 1, STAFCommandParser::kValueNotAllowed);
1793 fListParser.addOption(
1794 "SORTBYMODTIME", 1, STAFCommandParser::kValueNotAllowed);
1795 fListParser.addOption(
1796 "CASESENSITIVE", 1, STAFCommandParser::kValueNotAllowed);
1797 fListParser.addOption(
1798 "CASEINSENSITIVE", 1, STAFCommandParser::kValueNotAllowed);
1799 fListParser.addOption(
1800 "TYPE", 1, STAFCommandParser::kValueRequired);
1801 fListParser.addOption(
1802 "RECURSE", 1, STAFCommandParser::kValueNotAllowed);
1803 fListParser.addOption(
1804 "SETTINGS", 1, STAFCommandParser::kValueNotAllowed);
1805
1806 fListParser.addOptionGroup("DIRECTORY SETTINGS", 1, 1);
1807 fListParser.addOptionGroup("SORTBYNAME SORTBYSIZE SORTBYTIME", 0, 1);
1808 fListParser.addOptionGroup("CASESENSITIVE CASEINSENSITIVE", 0, 1);
1809 fListParser.addOptionGroup("LONG SUMMARY", 0, 1);
1810
1811 fListParser.addOptionNeed("LIST", "DIRECTORY SETTINGS");
1812 fListParser.addOptionNeed(
1813 "NAME EXT LONG SUMMARY SORTBYNAME SORTBYSIZE SORTBYMODTIME TYPE RECURSE",
1814 "DIRECTORY");
1815 fListParser.addOptionNeed("DETAILS", "LONG");
1816 fListParser.addOptionNeed("CASESENSITIVE CASEINSENSITIVE",
1817 "NAME EXT SORTBYNAME");
1818
1819 // LIST COPYREQUESTS parser setup
1820
1821 fListCopyRequestsParser.addOption(
1822 "LIST", 1, STAFCommandParser::kValueNotAllowed);
1823 fListCopyRequestsParser.addOption(
1824 "COPYREQUESTS", 1, STAFCommandParser::kValueNotAllowed);
1825 fListCopyRequestsParser.addOption(
1826 "INBOUND", 1, STAFCommandParser::kValueNotAllowed);
1827 fListCopyRequestsParser.addOption(
1828 "OUTBOUND", 1, STAFCommandParser::kValueNotAllowed);
1829 fListCopyRequestsParser.addOption(
1830 "FILE", 1, STAFCommandParser::kValueNotAllowed);
1831 fListCopyRequestsParser.addOption(
1832 "DIRECTORY", 1, STAFCommandParser::kValueNotAllowed);
1833 fListCopyRequestsParser.addOption(
1834 "BINARY", 1, STAFCommandParser::kValueNotAllowed);
1835 fListCopyRequestsParser.addOption(
1836 "TEXT", 1, STAFCommandParser::kValueNotAllowed);
1837 fListCopyRequestsParser.addOption(
1838 "LONG", 1, STAFCommandParser::kValueNotAllowed);
1839
1840 fListCopyRequestsParser.addOptionNeed("BINARY TEXT", "FILE");
1841
1842 // CREATE parser setup
1843
1844 fCreateParser.addOption("CREATE", 1,
1845 STAFCommandParser::kValueNotAllowed);
1846 fCreateParser.addOption("DIRECTORY", 1,
1847 STAFCommandParser::kValueRequired);
1848 fCreateParser.addOption("FULLPATH", 1,
1849 STAFCommandParser::kValueNotAllowed);
1850 fCreateParser.addOption("FAILIFEXISTS", 1,
1851 STAFCommandParser::kValueNotAllowed);
1852
1853 fCreateParser.addOptionNeed("CREATE", "DIRECTORY");
1854
1855 // DELETE parser setup
1856
1857 fDeleteParser.addOption("DELETE", 1,
1858 STAFCommandParser::kValueNotAllowed);
1859 fDeleteParser.addOption("ENTRY", 1,
1860 STAFCommandParser::kValueRequired);
1861 fDeleteParser.addOption("CHILDREN", 1,
1862 STAFCommandParser::kValueNotAllowed);
1863 fDeleteParser.addOption("NAME", 1,
1864 STAFCommandParser::kValueRequired);
1865 fDeleteParser.addOption("EXT", 1,
1866 STAFCommandParser::kValueRequired);
1867 fDeleteParser.addOption("TYPE", 1,
1868 STAFCommandParser::kValueRequired);
1869 fDeleteParser.addOption("CASESENSITIVE", 1,
1870 STAFCommandParser::kValueNotAllowed);
1871 fDeleteParser.addOption("CASEINSENSITIVE", 1,
1872 STAFCommandParser::kValueNotAllowed);
1873 fDeleteParser.addOption("RECURSE", 1,
1874 STAFCommandParser::kValueNotAllowed);
1875 fDeleteParser.addOption("CONFIRM", 1,
1876 STAFCommandParser::kValueNotAllowed);
1877 fDeleteParser.addOption("IGNOREERRORS", 1,
1878 STAFCommandParser::kValueNotAllowed);
1879
1880 fDeleteParser.addOptionGroup("CASESENSITIVE CASEINSENSITIVE", 0, 1);
1881
1882 fDeleteParser.addOptionNeed("DELETE", "ENTRY");
1883 fDeleteParser.addOptionNeed("DELETE", "CONFIRM");
1884 fDeleteParser.addOptionNeed("NAME EXT TYPE", "CHILDREN");
1885 fDeleteParser.addOptionNeed("CASESENSITIVE CASEINSENSITIVE", "NAME EXT");
1886 fDeleteParser.addOptionNeed("IGNOREERRORS", "CHILDREN RECURSE");
1887
1888 // QUERY parser setup
1889
1890 fQueryParser.addOption("QUERY", 1,
1891 STAFCommandParser::kValueNotAllowed);
1892 fQueryParser.addOption("ENTRY", 1,
1893 STAFCommandParser::kValueRequired);
1894
1895 fQueryParser.addOptionNeed("QUERY", "ENTRY");
1896
1897 // SET parser setup
1898
1899 fSetParser.addOption("SET", 1,
1900 STAFCommandParser::kValueNotAllowed);
1901 fSetParser.addOption("STRICTFSCOPYTRUST", 1,
1902 STAFCommandParser::kValueRequired);
1903
1904 // set groups/needs
1905
1906 fSetParser.addOptionGroup("STRICTFSCOPYTRUST", 1, 1);
1907
1908 // Construct map-class for a LIST DIRECTORY LONG information
1909
1910 fListLongInfoClass = STAFMapClassDefinition::create(
1911 "STAF/Service/FS/ListLongInfo");
1912
1913 fListLongInfoClass->addKey("type", "Type");
1914 fListLongInfoClass->addKey("size", "Size");
1915 fListLongInfoClass->addKey("lastModifiedTimestamp",
1916 "Modified Date-Time");
1917 fListLongInfoClass->addKey("name", "Name");
1918 fListLongInfoClass->addKey("linkTarget", "Link Target");
1919 fListLongInfoClass->setKeyProperty(
1920 "linkTarget", "display-short-name", "Link");
1921
1922 // Construct map-class for LIST DIRECTORY LONG DETAILS information
1923
1924 fListDetailsInfoClass = STAFMapClassDefinition::create(
1925 "STAF/Service/FS/ListDetailsInfo");
1926
1927 fListDetailsInfoClass->addKey("name", "Name");
1928 fListDetailsInfoClass->addKey("linkTarget", "Link Target");
1929 fListDetailsInfoClass->setKeyProperty(
1930 "linkTarget", "display-short-name", "Link");
1931 fListDetailsInfoClass->addKey("type", "Type");
1932 fListDetailsInfoClass->addKey("size", "Size");
1933 fListDetailsInfoClass->addKey("upperSize", "U-Size");
1934 fListDetailsInfoClass->addKey("lowerSize", "L-Size");
1935 fListDetailsInfoClass->addKey("lastModifiedTimestamp",
1936 "Modified Date-Time");
1937
1938 // Construct map-class for a LIST DIRECTORY SUMMARY information
1939
1940 fListSummaryInfoClass = STAFMapClassDefinition::create(
1941 "STAF/Service/FS/ListSummaryInfo");
1942
1943 fListSummaryInfoClass->addKey("name", "Name");
1944 fListSummaryInfoClass->addKey("size", "Size");
1945 fListSummaryInfoClass->addKey("numFiles", "Files");
1946 fListSummaryInfoClass->addKey("numDirectories", "Directories");
1947
1948 // Construct map class for LIST COPYREQUESTS information
1949
1950 fCopyRequestClass = STAFMapClassDefinition::create(
1951 "STAF/Service/FS/CopyRequest");
1952
1953 fCopyRequestClass->addKey("startTimestamp", "Start Date-Time");
1954 fCopyRequestClass->setKeyProperty(
1955 "timestamp", "display-short-name", "Date-Time");
1956 fCopyRequestClass->addKey("io", "In/Out");
1957 fCopyRequestClass->setKeyProperty(
1958 "io", "display-short-name", "I/O");
1959 fCopyRequestClass->addKey("machine", "Machine");
1960 fCopyRequestClass->addKey("name", "Name");
1961 fCopyRequestClass->addKey("type", "Type");
1962
1963 // Construct map class for COPYREQUESTS LONG information for a file copy
1964
1965 fCopyFileClass = STAFMapClassDefinition::create(
1966 "STAF/Service/FS/CopyFile");
1967
1968 fCopyFileClass->addKey("startTimestamp", "Start Date-Time");
1969 fCopyFileClass->setKeyProperty(
1970 "timestamp", "display-short-name", "Date-Time");
1971 fCopyFileClass->addKey("io", "In/Out");
1972 fCopyFileClass->setKeyProperty(
1973 "io", "display-short-name", "I/O");
1974 fCopyFileClass->addKey("machine", "Machine");
1975 fCopyFileClass->addKey("name", "File Name");
1976 fCopyFileClass->addKey("type", "Type");
1977 fCopyFileClass->addKey("mode", "Mode");
1978 fCopyFileClass->addKey("state", "Transfer State");
1979
1980 // Construct map class for the state of a file copy request
1981
1982 fFileCopyStateClass = STAFMapClassDefinition::create(
1983 "STAF/Service/FS/FileCopyState");
1984 fFileCopyStateClass->addKey("fileSize", "File Size");
1985 fFileCopyStateClass->addKey("bytesCopied", "Bytes Copied");
1986
1987 // Construct map class for COPYREQUESTS LONG information for a directory
1988
1989 fCopyDirectoryClass = STAFMapClassDefinition::create(
1990 "STAF/Service/FS/CopyDirectory");
1991
1992 fCopyDirectoryClass->addKey("startTimestamp", "Start Date-Time");
1993 fCopyDirectoryClass->setKeyProperty(
1994 "timestamp", "display-short-name", "Date-Time");
1995 fCopyDirectoryClass->addKey("io", "In/Out");
1996 fCopyDirectoryClass->setKeyProperty(
1997 "io", "display-short-name", "I/O");
1998 fCopyDirectoryClass->addKey("machine", "Machine");
1999 fCopyDirectoryClass->addKey("name", "Directory Name");
2000 fCopyDirectoryClass->addKey("type", "Type");
2001 fCopyDirectoryClass->addKey("state", "Transfer State");
2002
2003 // Construct map class for the state of a directory copy request
2004
2005 fDirectoryCopyStateClass = STAFMapClassDefinition::create(
2006 "STAF/Service/FS/DirectoryCopyState");
2007 fDirectoryCopyStateClass->addKey("name", "Name");
2008 fDirectoryCopyStateClass->addKey("mode", "Mode");
2009 fDirectoryCopyStateClass->addKey("fileSize", "File Size");
2010 fDirectoryCopyStateClass->addKey("bytesCopied", "Bytes Copied");
2011
2012 // Construct map class for LIST SETTINGS information
2013
2014 fSettingsClass = STAFMapClassDefinition::create(
2015 "STAF/Service/FS/Settings");
2016
2017 fSettingsClass->addKey("strictFSCopyTrust", "Strict FS Copy Trust");
2018
2019 // Construct map-class for GET ENTRY SIZE information
2020
2021 fEntrySizeInfoClass = STAFMapClassDefinition::create(
2022 "STAF/Service/FS/SizeInfo");
2023
2024 fEntrySizeInfoClass->addKey("size", "Size");
2025 fEntrySizeInfoClass->addKey("upperSize", "Upper 32-bit Size");
2026 fEntrySizeInfoClass->addKey("lowerSize", "Lower 32-bit Size");
2027
2028 // Construct map-class for QUERY ENTRY information
2029
2030 fQueryInfoClass = STAFMapClassDefinition::create(
2031 "STAF/Service/FS/QueryInfo");
2032
2033 fQueryInfoClass->addKey("name", "Name");
2034 fQueryInfoClass->addKey("linkTarget", "Link Target");
2035 fQueryInfoClass->addKey("type", "Type");
2036 fQueryInfoClass->addKey("size", "Size");
2037 fQueryInfoClass->addKey("upperSize", "Upper 32-bit Size");
2038 fQueryInfoClass->addKey("lowerSize", "Lower 32-bit Size");
2039 fQueryInfoClass->addKey("lastModifiedTimestamp", "Modified Date-Time");
2040
2041 // Construct map-class for error information on a copy/delete
2042
2043 fErrorInfoClass = STAFMapClassDefinition::create(
2044 "STAF/Service/FS/ErrorInfo");
2045
2046 fErrorInfoClass->addKey("name", "Name");
2047 fErrorInfoClass->addKey("rc", "RC");
2048 fErrorInfoClass->addKey("osRC", "OS RC");
2049
2050 #ifdef STAF_USE_SSL
2051 // Perform SSL Thread Setup and assign callback functions needed for
2052 // multi-threaded applications that use OpenSSL
2053 // Note: Need to do this because the FS service uses OpenSSL functions
2054 // for determining the checksum of files
2055
2056 STAF_SSL_Thread_Setup();
2057 #endif
2058 }
2059
2060
~STAFFSService()2061 STAFFSService::~STAFFSService()
2062 {
2063 #ifdef STAF_USE_SSL
2064 // Free SSL Thread callbacks and mutexes used by the locking
2065 // callback function
2066 // Note: Need to do this because the FS service uses OpenSSL functions
2067 // for determining the checksum of files
2068
2069 STAF_SSL_Thread_Cleanup();
2070 #endif
2071 }
2072
2073
info(unsigned int) const2074 STAFString STAFFSService::info(unsigned int) const
2075 {
2076 return name() + ": Internal";
2077 }
2078
2079
acceptRequest(const STAFServiceRequest & requestInfo)2080 STAFServiceResult STAFFSService::acceptRequest(
2081 const STAFServiceRequest &requestInfo)
2082 {
2083 STAFString action = requestInfo.fRequest.subWord(0, 1).toLowerCase();
2084 STAFString subAction = requestInfo.fRequest.subWord(1, 1).toLowerCase();
2085
2086 if (action == "copy")
2087 {
2088 if (subAction == "file")
2089 return handleCopyFile(requestInfo);
2090 else if (subAction == "directory")
2091 return handleCopyDir(requestInfo);
2092 else
2093 {
2094 STAFString errMsg = STAFString("'") +
2095 requestInfo.fRequest.subWord(0, 1) + " " +
2096 requestInfo.fRequest.subWord(1, 1) +
2097 "' is not a valid command request for the " + name() +
2098 " service" + *gLineSeparatorPtr + *gLineSeparatorPtr +
2099 sHelpMsg;
2100
2101 return STAFServiceResult(kSTAFInvalidRequestString, errMsg);
2102 }
2103 }
2104 else if (action == "move")
2105 {
2106 if (subAction == "file")
2107 return handleMove(true, requestInfo);
2108 else if (subAction == "directory")
2109 return handleMove(false, requestInfo);
2110 else
2111 {
2112 STAFString errMsg = STAFString("'") +
2113 requestInfo.fRequest.subWord(0, 1) + " " +
2114 requestInfo.fRequest.subWord(1, 1) +
2115 "' is not a valid command request for the " + name() +
2116 " service" + *gLineSeparatorPtr + *gLineSeparatorPtr +
2117 sHelpMsg;
2118
2119 return STAFServiceResult(kSTAFInvalidRequestString, errMsg);
2120 }
2121 }
2122 else if (action == "get") return handleGet(requestInfo);
2123 else if (action == "list")
2124 {
2125 if (subAction == "copyrequests")
2126 return handleListCopyRequests(requestInfo);
2127 else
2128 return handleList(requestInfo);
2129 }
2130 else if (action == "create") return handleCreate(requestInfo);
2131 else if (action == "delete") return handleDelete(requestInfo);
2132 else if (action == "query") return handleQuery(requestInfo);
2133 else if (action == "set") return handleSet(requestInfo);
2134 else if (action == "help") return handleHelp(requestInfo);
2135 else
2136 {
2137 STAFString errMsg = STAFString("'") +
2138 requestInfo.fRequest.subWord(0, 1) +
2139 "' is not a valid command request for the " + name() +
2140 " service" + *gLineSeparatorPtr + *gLineSeparatorPtr +
2141 sHelpMsg;
2142
2143 return STAFServiceResult(kSTAFInvalidRequestString, errMsg);
2144 }
2145 }
2146
2147
handleCopyFile(const STAFServiceRequest & requestInfo)2148 STAFServiceResult STAFFSService::handleCopyFile(
2149 const STAFServiceRequest &requestInfo)
2150 {
2151 // Verify that the requesting machine/user has at least trust level 4
2152
2153 IVALIDATE_TRUST(4, "COPY");
2154
2155 // Parse the request
2156
2157 STAFCommandParseResultPtr parsedResult = fCopyFileParser.parse(
2158 requestInfo.fRequest);
2159
2160 if (parsedResult->rc != kSTAFOk)
2161 {
2162 return STAFServiceResult(kSTAFInvalidRequestString,
2163 parsedResult->errorBuffer, 0);
2164 }
2165
2166 DEFINE_VAR_POOL_LIST(varPoolList, varPoolListSize, requestInfo);
2167 STAFString fromMachine = requestInfo.fEndpoint;
2168 STAFHandle_t handle = requestInfo.fHandle;
2169 STAFString request = requestInfo.fRequest;
2170 STAFRC_t rc = kSTAFOk;
2171 STAFString toMachine = fromMachine;
2172 STAFString toFile;
2173 STAFString fromFile;
2174 STAFString errorBuffer;
2175
2176 rc = RESOLVE_STRING_OPTION("FILE", fromFile);
2177
2178 if (!rc) rc = RESOLVE_OPTIONAL_STRING_OPTION("TOMACHINE", toMachine);
2179
2180 if (rc) return STAFServiceResult(rc, errorBuffer);
2181
2182 // if user specified TOFILE value
2183 if (parsedResult->optionTimes("TOFILE") != 0)
2184 {
2185 toFile = parsedResult->optionValue("TOFILE");
2186 }
2187 else if (parsedResult->optionTimes("TODIRECTORY") != 0)
2188 {
2189 // Copy the file to this directory using the same file name as
2190 // the "from" file name
2191 toFile = parsedResult->optionValue("TODIRECTORY");
2192 }
2193 else
2194 {
2195 toFile = parsedResult->optionValue("FILE");
2196 }
2197
2198 // Note: We'll resolve any variables in TOFILE on the TOMACHINE not
2199 // here on the from machine.
2200
2201 // Check if the from file exists
2202
2203 STAFFSPath fromPath(fromFile);
2204
2205 try
2206 {
2207 if (!fromPath.exists())
2208 return STAFServiceResult(
2209 kSTAFDoesNotExist, "File " + fromFile + " does not exist");
2210 }
2211 catch (STAFBaseOSErrorException &e)
2212 {
2213 STAFString errMsg = "Error on From File: " + fromFile + "\n" +
2214 e.getText() + STAFString(": ") + e.getErrorCode();
2215
2216 return STAFServiceResult(kSTAFBaseOSError, errMsg);
2217 }
2218
2219 // Get the actual path name and remove any unnecessary trailing slashes
2220 fromFile = fromPath.setRoot(fromPath.root()).asString();
2221
2222 // If TODIRECTORY is specified, need to add the from file name to the path
2223 if (parsedResult->optionTimes("TODIRECTORY") != 0)
2224 {
2225 toFile = toFile + "/" + fromPath.name();
2226
2227 if (fromPath.extension() != "")
2228 toFile = toFile + "." + fromPath.extension();
2229 }
2230
2231 // determine if transfer is text or binary
2232 bool doText = false;
2233 bool doCodepage = false;
2234 STAFString newEOL = "Native";
2235
2236 if (parsedResult->optionTimes("TEXT") > 0)
2237 {
2238 doText = true;
2239 doCodepage = true;
2240
2241 rc = RESOLVE_OPTIONAL_STRING_OPTION("FORMAT", newEOL);
2242 if (rc) return STAFServiceResult(rc, errorBuffer);
2243
2244 // If enable NOCONVERT option, uncomment the following line
2245 //doCodepage = (parsedResult->optionTimes("NOCONVERT") == 0);
2246 }
2247
2248 fstream inFile;
2249
2250 // open the file as binary
2251 inFile.open(fromFile.toCurrentCodePage()->buffer(),
2252 ios::in | STAF_ios_binary);
2253
2254 if (!inFile)
2255 return STAFServiceResult(kSTAFFileOpenError, fromFile);
2256
2257 // Get the size of the file (upperSize and lowerSize).
2258 // If the file size is < 4G, upperSize will be zero.
2259
2260 STAFFSEntryPtr entry;
2261
2262 try
2263 {
2264 entry = fromPath.getEntry();
2265 }
2266 catch (STAFBaseOSErrorException &e)
2267 {
2268 STAFString errMsg = "Error on From File: " + fromFile + "\n" +
2269 e.getText() + STAFString(": ") + e.getErrorCode();
2270
2271 return STAFServiceResult(kSTAFBaseOSError, errMsg);
2272 }
2273
2274 unsigned int upperSize = entry->size().first;
2275 unsigned int lowerSize = entry->size().second;
2276
2277 // Check if file size exceeds the maximum that the FS service handles
2278
2279 if (upperSize > 0)
2280 {
2281 STAFString errMsg = STAFString(
2282 "File size exceeds the maximum size (") + UINT_MAX +
2283 ") supported. File name: " + fromFile;
2284 return STAFServiceResult(kSTAFFileReadError, errMsg);
2285 }
2286
2287 unsigned int fileLength = lowerSize;
2288
2289 unsigned char fileBuffer[4000] = { 0 };
2290 unsigned int writeLength = 0;
2291 STAFConnectionPtr connection;
2292 STAFConnectionProviderPtr provider;
2293 STAFString result;
2294 unsigned int useNewAPI = 1;
2295 unsigned int levelToUse = 0;
2296 unsigned int flags = 0;
2297
2298 if (parsedResult->optionTimes("FAILIFEXISTS") != 0)
2299 flags |= 0x00000001;
2300 else if (parsedResult->optionTimes("FAILIFNEW") != 0)
2301 flags |= 0x00000002;
2302
2303 // If interface cycling is not enabled, and toMachine is not 'local',
2304 // and neither interface nor port are specified in toMachine, get the
2305 // originator's interface and prepend to the toMachine value so that
2306 // the connection to the toMachine will use the orginator's interface.
2307
2308 if ((!gConnectionManagerPtr->getAutoInterfaceCycling()) &&
2309 (!isLocalMachine(toMachine, 1)) &&
2310 (toMachine.find(gSpecSeparator == STAFString::kNPos)) &&
2311 (toMachine.find(kUTF8_AT) == STAFString::kNPos))
2312 {
2313 unsigned int specSepPos = requestInfo.fEndpoint.find(gSpecSeparator);
2314
2315 if (specSepPos != STAFString::kNPos)
2316 {
2317 STAFString interface = requestInfo.fEndpoint.subString(
2318 0, specSepPos);
2319
2320 if (interface != "local")
2321 {
2322 // Prepend the interface from the originator's endpoint
2323 toMachine = interface + gSpecSeparator + toMachine;
2324 }
2325 }
2326 }
2327
2328 // This flag indicates if copyDataPtr has been initialized yet by calling
2329 // gFSCopyManagerPtr->add() and passing it copyDataPtr
2330
2331 bool addedFSCopyData = false;
2332
2333 STAFFSCopyManager::FSCopyDataPtr copyDataPtr;
2334
2335 try
2336 {
2337 // Make a connection to the toMachine
2338
2339 try
2340 {
2341 rc = gConnectionManagerPtr->makeConnection(
2342 toMachine, provider, connection, result);
2343 }
2344 catch (STAFConnectionProviderConnectException &e)
2345 {
2346 rc = kSTAFNoPathToMachine;
2347 result = e.getText() + STAFString(": ") +
2348 STAFString(e.getErrorCode());
2349 }
2350
2351 if ((rc == kSTAFNoPathToMachine) &&
2352 (toMachine.find(kUTF8_AT) == STAFString::kNPos))
2353 {
2354 // Retry connecting to the toMachine, this time using the
2355 // originator's port
2356
2357 unsigned int atPos = requestInfo.fEndpoint.find(kUTF8_AT);
2358
2359 if (atPos != STAFString::kNPos)
2360 {
2361 toMachine = toMachine + requestInfo.fEndpoint.subString(atPos);
2362
2363 rc = gConnectionManagerPtr->makeConnection(
2364 toMachine, provider, connection, result);
2365 }
2366 }
2367
2368 if (rc) return STAFServiceResult(rc, result);
2369
2370 // First, lets try the new API
2371
2372 connection->writeUInt(kSTAFFileTransferAPI2); // New API number
2373 connection->writeUInt(0); // Dummy level
2374
2375 STAFRC_t ack = connection->readUInt();
2376
2377 if (ack != kSTAFOk)
2378 {
2379 // They don't support the new API, so try the old API
2380 useNewAPI = 0;
2381
2382 rc = gConnectionManagerPtr->makeConnection(
2383 toMachine, connection, result);
2384
2385 if (rc) return STAFServiceResult(rc, result);
2386
2387 connection->writeUInt(kSTAFFileTransferAPI); // Old API Number
2388 connection->writeUInt(0); // API Level
2389
2390 ack = connection->readUInt();
2391
2392 if (ack != kSTAFOk) return ack;
2393 }
2394 else
2395 {
2396 // Now find out the specific level to use
2397 unsigned int minLevel = 1;
2398 unsigned int maxLevel = 3;
2399
2400 connection->writeUInt(minLevel);
2401 connection->writeUInt(maxLevel);
2402
2403 levelToUse = connection->readUInt();
2404
2405 if (levelToUse == 0) return kSTAFInvalidAPILevel;
2406 }
2407
2408 // If the other machine can do a text transfer, specify text or binary
2409
2410 if (useNewAPI && (levelToUse > 1))
2411 {
2412 if (doText)
2413 {
2414 if (doCodepage)
2415 connection->writeUInt(kSTAFFSTextConvert);
2416 else
2417 connection->writeUInt(kSTAFFSTextNoConvert);
2418 }
2419 else
2420 {
2421 connection->writeUInt(kSTAFFSBinary);
2422 }
2423 }
2424
2425 connection->writeString(*gMachinePtr);
2426 connection->writeString(requestInfo.fMachine);
2427 connection->writeString(toFile);
2428
2429 if (!(useNewAPI && (levelToUse > 1)) && doText)
2430 {
2431 // Fail and abort
2432 flags |= (0x00000001 | 0x00000002);
2433
2434 // Send bad flags 0x1|0x2 // fail if new | fail if exist
2435 // to kill other side
2436 connection->writeUInt(flags);
2437
2438 // Read kill confirmation
2439 ack = static_cast<STAFRC_t>(connection->readUInt());
2440 result = connection->readString();
2441 inFile.close();
2442 return kSTAFInvalidAPILevel;
2443 }
2444
2445 // Add an entry to the FS Copy Map so can list copies in progress
2446
2447 int copyMode = kSTAFFSBinary;
2448
2449 if (doCodepage)
2450 copyMode = kSTAFFSTextConvert; // Text, cp conversion
2451 else if (doText)
2452 copyMode = kSTAFFSTextNoConvert; // Text, no cp conversion
2453
2454 if (gFSCopyManagerPtr->add(fromFile, toMachine, kSTAFFSCopyFrom,
2455 kSTAFFSFileCopy, copyMode,
2456 fileLength, copyDataPtr))
2457 {
2458 return STAFServiceResult(
2459 kSTAFFileReadError, "Cannot read from a file that another "
2460 "copy request is currently writing to");
2461 }
2462
2463 addedFSCopyData = true;
2464
2465 // Write the flags
2466
2467 connection->writeUInt(flags);
2468
2469 if (useNewAPI && levelToUse > 2)
2470 {
2471 connection->writeUInt(requestInfo.fHandle);
2472
2473 if (requiresSecureConnection(requestInfo.fAuthenticator) &&
2474 (provider->getProperty(
2475 kSTAFConnectionProviderIsSecureProperty) != "1"))
2476 {
2477 // Don't send authentication data since non-secure
2478 // connection. Instead set authenticator to "none" and
2479 // user to "anonymous" and set authentication data to ""
2480
2481 connection->writeString(gNoneString);
2482 connection->writeString(gAnonymousString);
2483 connection->writeString("");
2484 }
2485 else
2486 {
2487 connection->writeString(requestInfo.fAuthenticator);
2488 connection->writeString(requestInfo.fUserIdentifier);
2489 connection->writeString(requestInfo.fAuthenticationData);
2490 }
2491
2492 connection->writeString(requestInfo.fInterface);
2493 connection->writeString(requestInfo.fLogicalInterfaceID);
2494 connection->writeString(requestInfo.fPhysicalInterfaceID);
2495 connection->writeString(requestInfo.fSTAFInstanceUUID);
2496 connection->writeString(*gSTAFInstanceUUIDPtr);
2497
2498 // Write request var pool
2499
2500 STAFVariablePool::VariableMap requestVarMap =
2501 requestInfo.fRequestVarPool->getVariableMapCopy();
2502
2503 connection->writeUInt(requestVarMap.size());
2504
2505 for (STAFVariablePool::VariableMap::iterator requestIter =
2506 requestVarMap.begin();
2507 requestIter != requestVarMap.end();
2508 ++requestIter)
2509 {
2510 connection->writeString(requestIter->second.name);
2511 connection->writeString(requestIter->second.value);
2512 }
2513
2514 // Write source shared var pool
2515
2516 STAFVariablePool::VariableMap sourceSharedVarMap =
2517 requestInfo.fSourceSharedVarPool->getVariableMapCopy();
2518
2519 connection->writeUInt(sourceSharedVarMap.size());
2520
2521 for (STAFVariablePool::VariableMap::iterator sourceSharedIter =
2522 sourceSharedVarMap.begin();
2523 sourceSharedIter != sourceSharedVarMap.end();
2524 ++sourceSharedIter)
2525 {
2526 connection->writeString(sourceSharedIter->second.name);
2527 connection->writeString(sourceSharedIter->second.value);
2528 }
2529 }
2530
2531 // Check if can open and write to the file
2532
2533 ack = static_cast<STAFRC_t>(connection->readUInt());
2534 result = connection->readString();
2535
2536 if (ack != kSTAFOk)
2537 {
2538 gFSCopyManagerPtr->remove(copyDataPtr);
2539
2540 return STAFServiceResult(ack, result);
2541 }
2542
2543 STAFString currentEOL = STAFString("");
2544
2545 if (doText)
2546 {
2547 // Determine what line ending the from file contains
2548
2549 STAFServiceResult result = determineLineEnding(
2550 fileLength, inFile, fromFile, toMachine, currentEOL);
2551
2552 if (result.fRC != kSTAFOk)
2553 {
2554 gFSCopyManagerPtr->remove(copyDataPtr);
2555
2556 return result;
2557 }
2558
2559 currentEOL = result.fResult;
2560
2561 // send the new EOL marker across
2562 connection->writeString(newEOL);
2563
2564 // verify ok new eol
2565 if (connection->readUInt() == kSTAFFSStopCopy)
2566 {
2567 gFSCopyManagerPtr->remove(copyDataPtr);
2568
2569 return STAFServiceResult(kSTAFBaseOSError,
2570 "Get current EOL failure");
2571 }
2572
2573 newEOL = connection->readString();
2574
2575 if (newEOL.isEqualTo(currentEOL))
2576 {
2577 // Allows changing to use binary transfer (which is faster) if
2578 // the eol on both sides are the same and no convert is needed.
2579
2580 connection->writeUInt(kSTAFFSBinary);
2581 doText = false;
2582 }
2583 else
2584 connection->writeUInt(kSTAFFSTextNoConvert);
2585 }
2586
2587 if (doCodepage)
2588 {
2589 // Check if the codepages on both sides are the same because then
2590 // can use the text noconvert routine which is faster.
2591
2592 // Get this codepage id
2593 STAFString cPage;
2594 rc = RESOLVE_STRING("{STAF/Config/CodePage}", cPage);
2595
2596 // Get other codepage id
2597 STAFString otherCPage = connection->readString();
2598
2599 if (cPage.isEqualTo(otherCPage))
2600 {
2601 // XXX: Change next line to kSTAFFSTextNoConvert if decide not
2602 // to force codepage conversion on all text transfers
2603 connection->writeUInt(kSTAFFSTextConvert);
2604
2605 // XXX: Uncomment next line to enable the codepage filter.
2606 // Currently, commented out to force codepage conversion
2607 // on all text transfers.
2608 //doCodepage = false;
2609 }
2610 else
2611 connection->writeUInt(kSTAFFSTextConvert);
2612 }
2613
2614 /************** Start transferring the file ***************/
2615
2616 if (doCodepage)
2617 {
2618 // Perform a text transfer with conversion of eol chars and a
2619 // codepage conversion. It runs considerably slower than the
2620 // binary transfer. This is the type of transfer that will
2621 // occur if the TEXT option is specified and the codepages are
2622 // different. Data is sent as a series of buffers of UTF8 chars.
2623
2624 gFSCopyManagerPtr->updateFileCopy1(
2625 copyDataPtr, fileLength, kSTAFFSTextConvert);
2626
2627 unsigned int bytesCopied = 0;
2628
2629 connection->writeString(currentEOL);
2630
2631 if (fileLength > 0)
2632 {
2633 STAFStringBufferPtr eolStr = currentEOL.toCurrentCodePage();
2634
2635 // How many bytes in the end-of-line sequence
2636 unsigned int eolBufferSize = eolStr->length();
2637
2638 // Points to a buffer containing end-of-line sequence
2639 char *eolBuffer = new char[eolBufferSize];
2640 memcpy(eolBuffer, eolStr->buffer(), eolBufferSize);
2641
2642 // Last byte of end-of-line sequence
2643 char eolLastChar = eolBuffer[eolBufferSize - 1];
2644
2645 const unsigned int sBufferSize = 4096;
2646
2647 STAFRefPtr<char> buffer = STAFRefPtr<char>
2648 (new char[sBufferSize], STAFRefPtr<char>::INIT,
2649 STAFRefPtr<char>::ARRAY);
2650 unsigned int bufferSize = sBufferSize;
2651 unsigned int readOffset = 0; // Buffer read offset
2652 bool done = false;
2653
2654 while (!done)
2655 {
2656 rc = readFile(
2657 inFile, static_cast<char *>(buffer + readOffset),
2658 bufferSize - readOffset, fromFile,
2659 toMachine, fileLength, bytesCopied);
2660
2661 if (rc != kSTAFOk)
2662 {
2663 result = "Unrecoverable read error occurred while"
2664 " copying file " + fromFile + " in text mode";
2665 break;
2666 }
2667
2668 unsigned int bytesInBuffer = inFile.gcount() + readOffset;
2669
2670 bytesCopied += inFile.gcount();
2671
2672 if (bytesInBuffer < bufferSize) done = true;
2673
2674 // Find a newline. Make sure we don't underrun the buffer
2675
2676 unsigned int i = 0;
2677 unsigned int guardIndex = eolBufferSize - 1;
2678
2679 if (bytesInBuffer > 0)
2680 {
2681 i = bytesInBuffer - 1; // Last NewLine index
2682
2683 while (((buffer[i] != eolLastChar) ||
2684 !memcmp(buffer + i - eolBufferSize,
2685 eolBuffer, eolBufferSize)) &&
2686 (i > guardIndex))
2687 { --i; }
2688 }
2689
2690 while ((i == guardIndex) && !done)
2691 {
2692 // We have a line bigger than our buffer.
2693 // Note: the beginning of the buffer may be a lone
2694 // newline, but we ignore that for this algorithm
2695 // (as the next line is likely larger than the buffer
2696 // anyway.
2697
2698 // First, create a buffer that is double our current
2699 // size, and copy our existing buffer data into it
2700
2701 STAFRefPtr<char> tmpBuffer = STAFRefPtr<char>
2702 (new char[bufferSize * 2], STAFRefPtr<char>::INIT,
2703 STAFRefPtr<char>::ARRAY);
2704
2705 memcpy(tmpBuffer, buffer, bufferSize);
2706 buffer = tmpBuffer;
2707 bufferSize *= 2;
2708
2709 // Now, read in data to fill remainder of the buffer
2710
2711 rc = readFile(inFile, buffer + (bufferSize / 2),
2712 bufferSize / 2, fromFile, toMachine,
2713 fileLength, bytesCopied);
2714
2715 if (rc != kSTAFOk)
2716 {
2717 result = "Unrecoverable read error occurred while"
2718 " copying file " + fromFile + " in text mode";
2719 break;
2720 }
2721
2722 bytesInBuffer += inFile.gcount();
2723 bytesCopied += inFile.gcount();
2724
2725 // Finally, let's check to make sure that this buffer
2726 // was big enough by finding a newline. Otherwise,
2727 // let's run the loop again.
2728
2729 if (bytesInBuffer < bufferSize) done = true;
2730
2731 i = 0;
2732
2733 if (bytesInBuffer > 0)
2734 {
2735 i = bytesInBuffer - 1; // Last NewLine index
2736 guardIndex = (bufferSize / 2) - eolBufferSize;
2737
2738 while (((buffer[i] != eolLastChar) ||
2739 !memcmp(buffer + i - eolBufferSize,
2740 eolBuffer, eolBufferSize)) &&
2741 (i > guardIndex))
2742 { --i; }
2743 }
2744
2745 } // while ((i == guardIndex) && !done)
2746
2747 // We now have the last newline in the buffer
2748
2749 if (rc == kSTAFOk)
2750 {
2751 if (!done)
2752 {
2753 connection->writeUInt(kSTAFFSContinueCopy);
2754
2755 connection->writeString(
2756 STAFString(buffer, i + 1,
2757 STAFString::kCurrent));
2758
2759 memmove(buffer, buffer + i + 1,
2760 bufferSize - i - 1);
2761
2762 readOffset = bufferSize - i - 1;
2763 }
2764 else
2765 {
2766 connection->writeUInt(kSTAFFSContinueCopy);
2767
2768 connection->writeString(
2769 STAFString(buffer, bytesInBuffer,
2770 STAFString::kCurrent));
2771 }
2772
2773 gFSCopyManagerPtr->updateFileCopy(
2774 copyDataPtr, bytesCopied);
2775 }
2776 } // while (!done)
2777
2778 delete[] eolBuffer;
2779
2780 } // fileLength > 0
2781
2782 connection->writeUInt(kSTAFFSFinishedCopy);
2783
2784 inFile.close();
2785
2786 if (rc == kSTAFOk)
2787 {
2788 // Read an ack, so that we know the file is closed and
2789 // if the file was copied successfully
2790 rc = connection->readUInt();
2791 }
2792 }
2793 else if (doText)
2794 {
2795 // Text file copy without codepage conversion
2796 // Perform a text transfer with conversion of eol chars without a
2797 // codepage conversion. It runs considerably faster than the
2798 // codepage conversion transfer.
2799 // - This is the type of transfer that will occur if the NOCONVERT
2800 // option is enabled
2801 // - This is the type of transfer that will occur if the codepages
2802 // are the same and a text transfer has been specified
2803
2804 gFSCopyManagerPtr->updateFileCopy1(
2805 copyDataPtr, fileLength, kSTAFFSTextNoConvert);
2806
2807 STAFString transferString;
2808 int bufferSize = 3000;
2809 unsigned int transferLen = 0;
2810 char *buffer = new char[bufferSize];
2811 unsigned int bytesCopied = 0;
2812
2813 connection->writeString(currentEOL);
2814 connection->writeUInt(bufferSize);
2815
2816 while ((fileLength > 0) && (inFile.good()))
2817 {
2818 transferLen = STAF_MIN(bufferSize, fileLength);
2819
2820 rc = readFile(inFile, buffer, transferLen, fromFile,
2821 toMachine, fileLength, bytesCopied);
2822
2823 if (rc != kSTAFOk)
2824 {
2825 result = "Unrecoverable read error occurred while"
2826 " copying file " + fromFile +
2827 " in text (no codepage convert) mode";
2828 break;
2829 }
2830
2831 connection->writeUInt(transferLen);
2832 connection->write(buffer, transferLen);
2833
2834 fileLength -= transferLen;
2835 bytesCopied += transferLen;;
2836 gFSCopyManagerPtr->updateFileCopy(copyDataPtr, bytesCopied);
2837 }
2838
2839 connection->writeUInt(kSTAFFSFinishedCopy);
2840 delete[] buffer;
2841
2842 inFile.close();
2843
2844 if (rc == kSTAFOk)
2845 {
2846 // Read an ack, so that we know the file is closed and
2847 // if the file was copied successfully
2848 rc = connection->readUInt();
2849 }
2850 }
2851 else if (useNewAPI)
2852 {
2853 // Binary file copy (using new API)
2854
2855 connection->writeUInt(fileLength);
2856
2857 unsigned int bytesCopied = 0;
2858
2859 gFSCopyManagerPtr->updateFileCopy1(
2860 copyDataPtr, fileLength, kSTAFFSBinary);
2861
2862 while ((fileLength > 0) && inFile.good())
2863 {
2864 writeLength = STAF_MIN(sizeof(fileBuffer), fileLength);
2865
2866 rc = readFile(inFile, reinterpret_cast<char *>(fileBuffer),
2867 writeLength, fromFile, toMachine, fileLength,
2868 bytesCopied);
2869
2870 if (rc != kSTAFOk)
2871 {
2872 break;
2873 }
2874
2875 connection->write(fileBuffer, writeLength);
2876 fileLength -= writeLength;
2877 bytesCopied += writeLength;
2878 gFSCopyManagerPtr->updateFileCopy(copyDataPtr, bytesCopied);
2879 }
2880
2881 inFile.close();
2882
2883 if (rc == kSTAFOk)
2884 {
2885 // Read an ack, so that we know the file is closed and
2886 // if the file was copied successfully
2887 rc = connection->readUInt();
2888 }
2889 }
2890 else
2891 {
2892 // Binary file copy (using old API)
2893
2894 gFSCopyManagerPtr->updateFileCopy1(
2895 copyDataPtr, fileLength, kSTAFFSBinary);
2896
2897 unsigned bytesCopied = 0;
2898
2899 do
2900 {
2901 rc = readFile(inFile, reinterpret_cast<char *>(fileBuffer),
2902 sizeof(fileBuffer), fromFile, toMachine,
2903 fileLength, bytesCopied);
2904
2905 if (rc != kSTAFOk)
2906 {
2907 result = "Unrecoverable read error occurred while"
2908 " copying file " + fromFile +
2909 " in binary mode";
2910 break;
2911 }
2912
2913 writeLength = inFile.gcount();
2914 connection->writeUInt(writeLength);
2915
2916 if ((writeLength == 0) && !inFile.eof())
2917 {
2918 gFSCopyManagerPtr->remove(copyDataPtr);
2919
2920 return STAFServiceResult(kSTAFFileReadError, fromFile);
2921 }
2922 else if (writeLength != 0)
2923 {
2924 connection->write(fileBuffer, writeLength);
2925 ack = connection->readUInt();
2926 if (ack) result = connection->readString();
2927 fileLength -= writeLength;
2928 bytesCopied += writeLength;
2929 gFSCopyManagerPtr->updateFileCopy(copyDataPtr, bytesCopied);
2930 }
2931 }while ((writeLength != 0) && !ack && inFile.good());
2932
2933 inFile.close();
2934
2935 if (ack != kSTAFOk)
2936 {
2937 gFSCopyManagerPtr->remove(copyDataPtr);
2938
2939 return STAFServiceResult(ack, result);
2940 }
2941 else if (writeLength != 0)
2942 {
2943 // Tell the other side we are finished
2944
2945 connection->writeUInt(0);
2946
2947 // Read the final ack
2948
2949 try
2950 {
2951 ack = connection->readUInt();
2952 }
2953 catch (STAFConnectionIOException)
2954 {
2955 // Older clients will close the connection instead of
2956 // acking so we need to ignore Connection IO exceptions here
2957
2958 ack = kSTAFOk;
2959 }
2960
2961 if (ack != kSTAFOk)
2962 rc = ack;
2963 }
2964 }
2965 }
2966 catch (STAFConnectionProviderConnectException &e)
2967 {
2968 rc = kSTAFNoPathToMachine;
2969 result = e.getText() + STAFString(": ") + STAFString(e.getErrorCode());
2970 }
2971 catch (STAFConnectionIOException &e)
2972 {
2973 rc = kSTAFCommunicationError;
2974 result = e.getText() + STAFString(": ") + STAFString(e.getErrorCode());
2975 }
2976 catch (STAFException &e)
2977 {
2978 rc = e.getErrorCode();
2979
2980 if (rc == kSTAFConverterError)
2981 {
2982 result = e.getText() +
2983 STAFString(": Caught a STAF Converter Error in "
2984 "STAFFSService::handleCopyFile() while copying "
2985 "to file ") +
2986 toFile + " from machine " + fromMachine +
2987 ". The file contains data that is not valid in the"
2988 " codepage that STAF is using. To see the codepage that "
2989 "STAF is using, check the value of STAF variable "
2990 "STAF/Config/CodePage.";
2991 }
2992 else
2993 {
2994 result = e.getText() +
2995 STAFString(": Caught a STAFException in STAFFSService::"
2996 "handleCopyFile() while copying to file ") +
2997 toFile + " from machine " + fromMachine;
2998 }
2999 }
3000 catch (...)
3001 {
3002 rc = kSTAFUnknownError;
3003 result = "Caught unknown exception in STAFFSService::handleCopyFile() "
3004 "while copying to file " + toFile + " from machine " +
3005 fromMachine + "\n";
3006 }
3007
3008 if (addedFSCopyData)
3009 {
3010 // Remove file copy entry from the map
3011 gFSCopyManagerPtr->remove(copyDataPtr);
3012 }
3013
3014 return STAFServiceResult(rc, result);
3015 }
3016
3017
handleCopyDir(const STAFServiceRequest & requestInfo)3018 STAFServiceResult STAFFSService::handleCopyDir(
3019 const STAFServiceRequest &requestInfo)
3020 {
3021 // Verify that the requesting machine/user has at least trust level 4
3022
3023 IVALIDATE_TRUST(4, "COPY");
3024
3025 // Parse the request
3026
3027 STAFCommandParseResultPtr parsedResult = fCopyDirParser.parse(
3028 requestInfo.fRequest);
3029
3030 if (parsedResult->rc != kSTAFOk)
3031 {
3032 return STAFServiceResult(kSTAFInvalidRequestString,
3033 parsedResult->errorBuffer, 0);
3034 }
3035
3036 DEFINE_VAR_POOL_LIST(varPoolList, varPoolListSize, requestInfo);
3037 STAFString fromMachine = requestInfo.fEndpoint;
3038 STAFHandle_t handle = requestInfo.fHandle;
3039 STAFString request = requestInfo.fRequest;
3040 unsigned int entryTypesUInt = kSTAFFSFile | kSTAFFSDirectory;
3041 STAFFSCaseSensitive_t caseSensitive = kSTAFFSCaseDefault;
3042 STAFString toMachine = fromMachine;
3043 bool recurse = (parsedResult->optionTimes("RECURSE") > 0);
3044 bool keepEmptyDir = (parsedResult->optionTimes("KEEPEMPTYDIRECTORIES") > 0);
3045 bool onlyDir = (parsedResult->optionTimes("ONLYDIRECTORIES") > 0);
3046 bool ignoreErrors = (parsedResult->optionTimes("IGNOREERRORS") > 0);
3047 STAFString namePattern(kUTF8_STAR);
3048 STAFString extPattern(kUTF8_STAR);
3049 STAFString fromDir;
3050 STAFString toDir;
3051 STAFString typeString;
3052 STAFString result;
3053 STAFString ackResult;
3054 STAFString errorBuffer;
3055
3056 // Do not want to resolve TODIRECTORY on this machine. Need to
3057 // resolve on the target machine
3058
3059 if (parsedResult->optionTimes("TODIRECTORY") != 0)
3060 toDir = parsedResult->optionValue("TODIRECTORY");
3061 else
3062 toDir = parsedResult->optionValue("DIRECTORY");
3063
3064 if (parsedResult->optionTimes("CASESENSITIVE") != 0)
3065 caseSensitive = kSTAFFSCaseSensitive;
3066 else if (parsedResult->optionTimes("CASEINSENSITIVE") != 0)
3067 caseSensitive = kSTAFFSCaseInsensitive;
3068
3069 STAFRC_t rc = RESOLVE_STRING_OPTION("DIRECTORY", fromDir);
3070
3071 if (!rc) rc = RESOLVE_OPTIONAL_STRING_OPTION("TOMACHINE", toMachine);
3072 if (!rc) rc = RESOLVE_OPTIONAL_STRING_OPTION("NAME", namePattern);
3073 if (!rc) rc = RESOLVE_OPTIONAL_STRING_OPTION("EXT", extPattern);
3074
3075 if (rc) return STAFServiceResult(rc, errorBuffer);
3076
3077 // Obtain directory path from the value of DIRECTORY
3078 STAFFSPath directoryPath(fromDir);
3079
3080 STAFFSEntryPtr entry;
3081
3082 try
3083 {
3084 if (!directoryPath.exists())
3085 {
3086 ackResult = "Directory, " + fromDir + ", does Not Exist";
3087 return STAFServiceResult(kSTAFDoesNotExist, ackResult);
3088 }
3089
3090 entry = directoryPath.getEntry();
3091
3092 // Convert the fromDir to the full long path name
3093 // (e.g. with correct file separators, correct case if Windows,
3094 // no unnecessary trailing slashes, etc)
3095
3096 fromDir = entry->path().asString();
3097 }
3098 catch (STAFBaseOSErrorException &e)
3099 {
3100 result = "Error on Source Directory: " + fromDir +
3101 "\n" + e.getText() + STAFString(": ") + e.getErrorCode();
3102
3103 return STAFServiceResult(kSTAFBaseOSError, result);
3104 }
3105
3106 // if the value of DIRECTORY is not a directory, then stop here
3107 if (entry->type() != kSTAFFSDirectory)
3108 {
3109 ackResult = fromDir + " is Not a Directory";
3110 return STAFServiceResult(kSTAFInvalidValue, ackResult);
3111 }
3112
3113 STAFConnectionPtr connection;
3114 STAFConnectionProviderPtr provider;
3115 unsigned int levelToUse = 0;
3116 unsigned int flags = 0;
3117
3118 if (parsedResult->optionTimes("FAILIFEXISTS") != 0)
3119 flags |= 0x00000001;
3120 else if (parsedResult->optionTimes("FAILIFNEW") != 0)
3121 flags |= 0x00000002;
3122
3123 STAFString newEOL = "Native";
3124
3125 rc = RESOLVE_OPTIONAL_STRING_OPTION("FORMAT", newEOL);
3126 if (rc) return STAFServiceResult(rc, errorBuffer);
3127
3128 // If interface cycling is not enabled, and toMachine is not 'local',
3129 // and neither interface nor port are specified in toMachine, get the
3130 // originator's interface and prepend to the toMachine value so that
3131 // the connection to the toMachine will use the orginator's interface.
3132
3133 if ((!gConnectionManagerPtr->getAutoInterfaceCycling()) &&
3134 (!isLocalMachine(toMachine, 1)) &&
3135 (toMachine.find(gSpecSeparator == STAFString::kNPos)) &&
3136 (toMachine.find(kUTF8_AT) == STAFString::kNPos))
3137 {
3138 unsigned int specSepPos = requestInfo.fEndpoint.find(gSpecSeparator);
3139
3140 if (specSepPos != STAFString::kNPos)
3141 {
3142 STAFString interface = requestInfo.fEndpoint.subString(
3143 0, specSepPos);
3144
3145 if (interface != "local")
3146 {
3147 // Prepend the interface from the originator's endpoint
3148 toMachine = interface + gSpecSeparator + toMachine;
3149 }
3150 }
3151 }
3152
3153 /************** Start transferring the directory ***************/
3154
3155 // This flag indicates if copyDataPtr has been initialized yet by calling
3156 // gFSCopyManagerPtr->add() and passing it copyDataPtr
3157
3158 bool addedFSCopyData = false;
3159
3160 STAFFSCopyManager::FSCopyDataPtr copyDataPtr;
3161
3162 try
3163 {
3164 // Make a connection to the toMachine
3165
3166 try
3167 {
3168 rc = gConnectionManagerPtr->makeConnection(
3169 toMachine, provider, connection, result);
3170 }
3171 catch (STAFConnectionProviderConnectException &e)
3172 {
3173 rc = kSTAFNoPathToMachine;
3174 result = e.getText() + STAFString(": ") +
3175 STAFString(e.getErrorCode());
3176 }
3177
3178 if ((rc == kSTAFNoPathToMachine) &&
3179 (toMachine.find(kUTF8_AT) == STAFString::kNPos))
3180 {
3181 // Retry connecting to the toMachine, this time appending the
3182 // originator's port to the toMachine
3183
3184 unsigned int atPos = requestInfo.fEndpoint.find(kUTF8_AT);
3185
3186 if (atPos != STAFString::kNPos)
3187 {
3188 toMachine = toMachine + requestInfo.fEndpoint.subString(atPos);
3189
3190 rc = gConnectionManagerPtr->makeConnection(
3191 toMachine, provider, connection, result);
3192 }
3193 }
3194
3195 if (rc) return STAFServiceResult(rc, result);
3196
3197 // First, lets try the new API
3198
3199 connection->writeUInt(kSTAFDirectoryCopyAPI); // API number
3200 connection->writeUInt(0); // Dummy level
3201
3202 STAFRC_t ack = connection->readUInt();
3203
3204 // The client don't support the new API
3205 if (ack != kSTAFOk)
3206 return STAFServiceResult(ack, "No Support for Directory Copy API");
3207
3208 // Now find out the specific level to use
3209 unsigned int minLevel = 1;
3210 unsigned int maxLevel = 4;
3211
3212 connection->writeUInt(minLevel);
3213 connection->writeUInt(maxLevel);
3214
3215 levelToUse = connection->readUInt();
3216
3217 if (levelToUse == 0)
3218 return STAFServiceResult(kSTAFInvalidAPILevel,
3219 "Invalid API Level");
3220
3221 int numTextExtentions = parsedResult->optionTimes("TEXTEXT");
3222
3223 // This prevents attempts to transfer if invalid api
3224
3225 if ((levelToUse < 2) && ( numTextExtentions != 0))
3226 return STAFServiceResult(kSTAFInvalidAPILevel,
3227 "Invalid API Level");
3228
3229 STAFString currentEOL;
3230
3231 // Determine default current EOL
3232
3233 STAFConfigInfo sysInfo;
3234 STAFString_t eBuff;
3235 unsigned int osRC;
3236
3237 if (STAFUtilGetConfigInfo(&sysInfo, &eBuff, &osRC) != kSTAFOk)
3238 {
3239 // Kill transfer
3240 return STAFServiceResult(
3241 kSTAFBaseOSError,
3242 STAFString("Get current EOL failure. ") +
3243 STAFString(eBuff, STAFString::kShallow) +
3244 ", RC: " + osRC);
3245 }
3246
3247 currentEOL = sysInfo.lineSeparator;
3248
3249 // Make sure not doing a cyclic copy (where the source includes the
3250 // destination) when copying a directory using the RECURSE option
3251 // to the local machine
3252
3253 if (recurse)
3254 {
3255 // Check if toMachine is the same as the local (from) machine
3256
3257 // XXX: It would be great if we had a better way to check if
3258 // the toMachine is the same machine as the local machine.
3259 // Problems with the current method of submitting a MISC WHOAMI
3260 // request to the toMachine include:
3261 // 1) It only knows if the toMachine is running the same instance
3262 // of STAF since it uses the STAF UUID. If we stored a Global
3263 // UUID in shared memory, then we could compare the toMachine's
3264 // Global UUID with the local machine's Global UUID instead.
3265 // 2) It submits a request to the toMachine. We already have a
3266 // connection to toMachine so we could change it to read the
3267 // toMachine's Global UUID via this existing connection.
3268
3269 bool localToMachine = false;
3270
3271 if (isLocalMachine(toMachine, 1))
3272 {
3273 localToMachine = true;
3274 }
3275 else
3276 {
3277 // Submit a WhoAmI request to the toMachine to see if it's the
3278 // local machine
3279
3280 STAFResultPtr whoamiResult = gSTAFProcHandlePtr->submit(
3281 toMachine, "MISC", "WHOAMI");
3282
3283 if (whoamiResult->rc == kSTAFOk)
3284 {
3285 // Unmarshall the result and get if isLocalRequest is "Yes"
3286
3287 if (whoamiResult->rc == kSTAFOk)
3288 {
3289 STAFString isLocalMachine = whoamiResult->resultObj->
3290 get("isLocalRequest")->asString();
3291
3292 if (isLocalMachine == "Yes")
3293 {
3294 localToMachine = true;
3295 }
3296 }
3297 }
3298 }
3299
3300 if (localToMachine)
3301 {
3302 // Resolve any STAF variables in toDir on the local machine
3303 // (since it hasn't been resolved yet)
3304
3305 STAFString resToDir = toDir;
3306
3307 STAFResultPtr toDirResult = gSTAFProcHandlePtr->submit(
3308 "local", "VAR",
3309 "RESOLVE STRING " + STAFHandle::wrapData(toDir));
3310
3311 if (toDirResult->rc == kSTAFOk) resToDir = toDirResult->result;
3312
3313 // Convert the toDirectory to the full long path name
3314 // (e.g. with correct file separators, correct case if Windows,
3315 // no unnecessary trailing slashes, etc)
3316
3317 STAFFSPath toDirPath(resToDir);
3318 resToDir = toDirPath.setRoot(toDirPath.root()).asString();
3319
3320 // Compares the from directory and to directory names in a
3321 // "normalized" form to make sure that they don't specify the
3322 // same directory name and to make sure that the fromDir
3323 // doesn't start with (include) the to directory which would
3324 // mean it's a cyclic copy which we don't support.
3325
3326 unsigned int compareResult = STAFFileSystem::comparePaths(
3327 resToDir, fromDir);
3328
3329 if (compareResult == kSTAFFSDoesIncludePath)
3330 {
3331 return STAFServiceResult(
3332 kSTAFDirectoryCopyError,
3333 "Cannot perform a cyclic copy (the source includes the "
3334 "destination)");
3335 }
3336 else if (compareResult == kSTAFFSSamePath)
3337 {
3338 return STAFServiceResult(
3339 kSTAFFileWriteError,
3340 STAFString("Cannot write to directory ") + resToDir +
3341 " at the same time this request is reading from it");
3342 }
3343 }
3344 }
3345
3346 // Add an entry to the FS Copy Map so can list copies in progress
3347
3348 if (gFSCopyManagerPtr->add(fromDir, toMachine, kSTAFFSCopyFrom,
3349 kSTAFFSDirectoryCopy, kSTAFFSBinary,
3350 0, copyDataPtr))
3351 {
3352 return STAFServiceResult(
3353 kSTAFFileReadError,
3354 STAFString( "Cannot read from directory ") + fromDir +
3355 " at the same time another copy request is writing to it");
3356 }
3357
3358 addedFSCopyData = true;
3359
3360 connection->writeString(*gMachinePtr);
3361 connection->writeString(fromMachine);
3362 connection->writeString(toDir); // write the root of toDir
3363 connection->writeUInt(flags);
3364
3365 if (levelToUse > 2)
3366 {
3367 connection->writeUInt(requestInfo.fHandle);
3368
3369 if (requiresSecureConnection(requestInfo.fAuthenticator) &&
3370 (provider->getProperty(
3371 kSTAFConnectionProviderIsSecureProperty) != "1"))
3372 {
3373 // Don't send authentication data since non-secure
3374 // connection. Instead set authenticator to "none" and
3375 // user to "anonymous" and set authentication data to ""
3376
3377 connection->writeString(gNoneString);
3378 connection->writeString(gAnonymousString);
3379 connection->writeString("");
3380 }
3381 else
3382 {
3383 connection->writeString(requestInfo.fAuthenticator);
3384 connection->writeString(requestInfo.fUserIdentifier);
3385 connection->writeString(requestInfo.fAuthenticationData);
3386 }
3387
3388 connection->writeString(requestInfo.fInterface);
3389 connection->writeString(requestInfo.fLogicalInterfaceID);
3390 connection->writeString(requestInfo.fPhysicalInterfaceID);
3391 connection->writeString(requestInfo.fSTAFInstanceUUID);
3392 connection->writeString(*gSTAFInstanceUUIDPtr);
3393 }
3394
3395 if (levelToUse > 1)
3396 {
3397 connection->writeString(newEOL);
3398 }
3399
3400 if (levelToUse > 2)
3401 {
3402 // Write request var pool
3403
3404 STAFVariablePool::VariableMap requestVarMap =
3405 requestInfo.fRequestVarPool->getVariableMapCopy();
3406
3407 connection->writeUInt(requestVarMap.size());
3408
3409 for (STAFVariablePool::VariableMap::iterator requestIter =
3410 requestVarMap.begin();
3411 requestIter != requestVarMap.end();
3412 ++requestIter)
3413 {
3414 connection->writeString(requestIter->second.name);
3415 connection->writeString(requestIter->second.value);
3416 }
3417
3418 // Write source shared var pool
3419
3420 STAFVariablePool::VariableMap sourceSharedVarMap =
3421 requestInfo.fSourceSharedVarPool->getVariableMapCopy();
3422
3423 connection->writeUInt(sourceSharedVarMap.size());
3424
3425 for (STAFVariablePool::VariableMap::iterator sourceSharedIter =
3426 sourceSharedVarMap.begin();
3427 sourceSharedIter != sourceSharedVarMap.end();
3428 ++sourceSharedIter)
3429 {
3430 connection->writeString(sourceSharedIter->second.name);
3431 connection->writeString(sourceSharedIter->second.value);
3432 }
3433 }
3434
3435 ack = static_cast<STAFRC_t>(connection->readUInt());
3436 ackResult = connection->readString();
3437
3438 if (ack != kSTAFOk)
3439 {
3440 gFSCopyManagerPtr->remove(copyDataPtr);
3441 return STAFServiceResult(ack, ackResult);
3442 }
3443
3444 bool doCodepageConvert = false;
3445
3446 if (levelToUse > 1)
3447 {
3448 newEOL = connection->readString();
3449
3450 if (numTextExtentions > 0)
3451 {
3452 doCodepageConvert = true;
3453 // XXX: If enable NOCONVERT option, write above line with the
3454 // following commented line
3455 //doCodepageConvert = (parsedResult->optionTimes("NOCONVERT") == 0);
3456 connection->writeUInt(kSTAFFSTextConvert);
3457 }
3458 else
3459 {
3460 connection->writeUInt(kSTAFFSBinary);
3461 }
3462 }
3463
3464 if (doCodepageConvert)
3465 {
3466 // If the codepages on both sides are the same, use the text
3467 // noconvert routine which is faster.
3468
3469 // Get this codepage id
3470 STAFString cPage;
3471 rc = RESOLVE_STRING("{STAF/Config/CodePage}", cPage);
3472
3473 // Get other codepage id
3474 STAFString otherCPage = connection->readString();
3475
3476 if (cPage.isEqualTo(otherCPage))
3477 {
3478 // XXX: Uncomment this line to enable the codepage filter
3479 // instead of forcing codepage conversion
3480 //doCodepageConvert = false;
3481 }
3482 }
3483
3484 // Add the text extensions to a list
3485
3486 STAFString resExt;
3487 SET_STAFString TextExtensionList;
3488
3489 for (int i = 0; i < numTextExtentions; i++)
3490 {
3491 rc = RESOLVE_INDEXED_STRING_OPTION("TEXTEXT", i + 1, resExt);
3492 if (!rc) TextExtensionList.insert(resExt);
3493 }
3494
3495 // Create a marshalled list of error information when copying files
3496
3497 STAFObjectPtr mc = STAFObject::createMarshallingContext();
3498 mc->setMapClassDefinition(fErrorInfoClass->reference());
3499 STAFObjectPtr outputList = STAFObject::createList();
3500
3501 // Start copying files/directories
3502
3503 if (!recurse)
3504 {
3505 STAFFSEnumPtr fileEnum = entry->enumerate(namePattern, extPattern,
3506 STAFFSEntryType_t(entryTypesUInt & ~kSTAFFSDirectory),
3507 kSTAFFSNoSort, caseSensitive);
3508
3509 if (fileEnum->isValid())
3510 {
3511 copyDirectory(fileEnum, fromDir, connection,
3512 TextExtensionList, currentEOL, newEOL,
3513 doCodepageConvert, levelToUse, caseSensitive,
3514 outputList, copyDataPtr, toMachine);
3515
3516 mc->setRootObject(outputList);
3517 result = mc->marshall();
3518 }
3519 }
3520 else
3521 {
3522 recurseCopyDir(entry, namePattern, extPattern, fromDir,
3523 keepEmptyDir, onlyDir, entryTypesUInt,
3524 connection, caseSensitive, TextExtensionList,
3525 currentEOL, newEOL, levelToUse, doCodepageConvert,
3526 outputList, copyDataPtr, toMachine);
3527
3528 mc->setRootObject(outputList);
3529 result = mc->marshall();
3530 }
3531
3532 // Stop copying files/directories
3533
3534 connection->writeUInt(kSTAFFSStopCopy);
3535
3536 if (!ignoreErrors && (outputList->size() != 0))
3537 rc = kSTAFDirectoryCopyError;
3538 else
3539 {
3540 rc = kSTAFOk;
3541 result = STAFString();
3542 }
3543 }
3544 catch (STAFConnectionProviderException &e)
3545 {
3546 rc = kSTAFNoPathToMachine;
3547 result = e.getText() + STAFString(": ") + STAFString(e.getErrorCode());
3548 }
3549 catch (STAFConnectionIOException &e)
3550 {
3551 rc = kSTAFCommunicationError;
3552 result = e.getText() + STAFString(": ") + STAFString(e.getErrorCode());
3553 }
3554 catch (...)
3555 {
3556 rc = kSTAFDirectoryCopyError;
3557 result = "Caught unknown exception in STAFFSService::handleCopyDir() "
3558 "while copying to directory " + toDir + " from machine " +
3559 fromMachine + "\n";
3560 }
3561
3562 if (addedFSCopyData)
3563 {
3564 // Remove file copy entry from map keeping track of copies in progress
3565 gFSCopyManagerPtr->remove(copyDataPtr);
3566 }
3567
3568 return STAFServiceResult(rc, result);
3569 }
3570
3571 // If the fileName is not already surrounded in double quotes, enclose it in
3572 // double quotes if it contains one or more spaces (because that's needed for
3573 // the OS "move"/"mv" commands).
3574 //
3575 // For example: C:\Test 1 -> "C:\Test 1"
3576 //
3577 // However, on Unix, if the fileName contains one or more wildcards, *, in
3578 // addition to one or more spaces, then don't enclose the wildcard characters
3579 // in double quotes because then the shell won't expand them.
3580 //
3581 // For example: /tmp/Test 1/test* -> "/tmp/Test 1/test"*
3582 // /tmp/Test 1/test*.txt -> "/tmp/Test 1/test"*".txt"
3583 // /tmp/Test 1/*est*1**.txt* -> "/tmp/Test 1/"*"est"*"1"**".txt"*
3584 //
3585 // Input: String containing the file name
3586 // bool indicating whether or not to check for wildcards (*)
3587 // Output: String containing the updated file name
quote(STAFString fileName,bool checkForWildCards)3588 STAFString quote(STAFString fileName, bool checkForWildCards)
3589 {
3590 if (fileName.find(sSpace) == STAFString::kNPos)
3591 {
3592 // No need to quote since fileName does not contain any spaces
3593 return fileName;
3594 }
3595 else if (fileName.find(sDoubleQuote, 0, STAFString::kChar) == 0)
3596 {
3597 // The fileName is already in double quotes (starts with ")
3598 return fileName;
3599 }
3600
3601 if (!checkForWildCards)
3602 {
3603 // Add a double quote at the beginning and at the end of the fileName
3604 return sDoubleQuote + fileName + sDoubleQuote;
3605 }
3606
3607 #ifdef STAF_OS_TYPE_WIN32
3608 return sDoubleQuote + fileName + sDoubleQuote;
3609 #else
3610 // On Unix, if the fileName contains one or more wildcards, *, in addition
3611 // to one or more spaces, then don't enclose the wildcard characters in
3612 // double quotes because then the shell won't expand them.
3613
3614 if (fileName.find(sStar, 0, STAFString::kChar) == STAFString::kNPos)
3615 {
3616 return sDoubleQuote + fileName + sDoubleQuote;
3617 }
3618
3619 // File name contains wildcards and spaces so add quotes around everything
3620 // except the wildcards
3621
3622 STAFString newName = "";
3623
3624 unsigned int wildcardIndex = 0;
3625
3626 // Find first non-wildcard character
3627 unsigned int nonWildcardIndex = fileName.findFirstNotOf(
3628 sStar, STAFString::kChar);
3629
3630 // Add double quote before next non-wildcard character
3631
3632 newName += fileName.subString(0, nonWildcardIndex, STAFString::kChar) +
3633 sDoubleQuote;
3634
3635 while (nonWildcardIndex != STAFString::kNPos)
3636 {
3637 // Find next wildcard
3638
3639 wildcardIndex = fileName.findFirstOf(
3640 sStar, nonWildcardIndex + 1, STAFString::kChar);
3641
3642 if (wildcardIndex == STAFString::kNPos)
3643 {
3644 // No more wildcards
3645
3646 newName += fileName.subString(
3647 nonWildcardIndex, STAFString::kRemainder, STAFString::kChar) +
3648 sDoubleQuote;
3649 break;
3650 }
3651
3652 newName += fileName.subString(
3653 nonWildcardIndex, wildcardIndex - nonWildcardIndex,
3654 STAFString::kChar) +
3655 sDoubleQuote;
3656
3657 // Find next non-wildcard character
3658
3659 nonWildcardIndex = fileName.findFirstNotOf(
3660 sStar, wildcardIndex + 1, STAFString::kChar);
3661
3662 // Add the wildcard(s)
3663
3664 newName += fileName.subString(
3665 wildcardIndex, nonWildcardIndex - wildcardIndex,
3666 STAFString::kChar);
3667
3668 if (nonWildcardIndex != STAFString::kNPos)
3669 {
3670 wildcardIndex = nonWildcardIndex - 1;
3671 newName += sDoubleQuote;
3672 }
3673 }
3674
3675 return newName;
3676 #endif
3677 }
3678
handleMove(const bool fileSpecified,const STAFServiceRequest & requestInfo)3679 STAFServiceResult STAFFSService::handleMove(
3680 const bool fileSpecified,
3681 const STAFServiceRequest &requestInfo)
3682 {
3683 // This command only supports moving files from one place to another on
3684 // the same machine. In order to move files to a different machine,
3685 // we would need to either:
3686 // 1) Submit a STAF FS COPY FILE/DIRECTORY request to move the file/
3687 // directory and then if successful, submit a STAF FS DELETE ENTRY
3688 // request to remove the source file/directory, or
3689 // 2) Add new STAFProc API(s) to move a file/directory
3690 //
3691 // And we may want additional options to indicate if file(s) to be moved
3692 // are text files in order to handle changing line endings based on the
3693 // operating systeme the file(s) are being moved to and code page changes.
3694
3695
3696 // Verify that the requesting machine/user has at least trust level 4
3697
3698 IVALIDATE_TRUST(4, "MOVE");
3699
3700 STAFCommandParseResultPtr parsedResult;
3701 STAFString fromOptionName;
3702
3703 if (fileSpecified)
3704 {
3705 // Parse the MOVE FILE request
3706
3707 parsedResult = fMoveFileParser.parse(requestInfo.fRequest);
3708
3709 fromOptionName = "FILE";
3710 }
3711 else
3712 {
3713 // Parse the MOVE DIRECTORY request
3714
3715 parsedResult = fMoveDirParser.parse(requestInfo.fRequest);
3716
3717 fromOptionName = "DIRECTORY";
3718 }
3719
3720 if (parsedResult->rc != kSTAFOk)
3721 {
3722 return STAFServiceResult(kSTAFInvalidRequestString,
3723 parsedResult->errorBuffer, 0);
3724 }
3725
3726 DEFINE_VAR_POOL_LIST(varPoolList, varPoolListSize, requestInfo);
3727 STAFRC_t rc = kSTAFOk;
3728 STAFString errorBuffer;
3729 STAFString result;
3730
3731 // Resolve the value specified for ENTRY
3732
3733 STAFString fromEntry;
3734
3735 rc = RESOLVE_STRING_OPTION(fromOptionName, fromEntry);
3736
3737 if (rc) return STAFServiceResult(rc, errorBuffer);
3738
3739 // Check if the "FROM" entry exists unless it contains a "*" wildcard
3740 // and it resides on a Unix system
3741
3742 bool checkIfFromEntryExists = true;
3743
3744 #ifndef STAF_OS_TYPE_WIN32
3745 if (fromEntry.find("*") != STAFString::kNPos)
3746 checkIfFromEntryExists = false;
3747 #endif
3748
3749 if (checkIfFromEntryExists)
3750 {
3751 STAFFSPath fromEntryPath(fromEntry);
3752 STAFFSEntryPtr entry;
3753
3754 try
3755 {
3756 if (!fromEntryPath.exists())
3757 {
3758 return STAFServiceResult(
3759 kSTAFDoesNotExist,
3760 fromOptionName + " '" + fromEntry + "' does not exist");
3761 }
3762
3763 entry = fromEntryPath.getEntry();
3764
3765 // Convert the "FROM" entry to the full long path name
3766 // (e.g. with correct file separators, correct case if Windows,
3767 // no unnecessary trailing slashes, etc)
3768
3769 fromEntry = entry->path().asString();
3770 }
3771 catch (STAFBaseOSErrorException &e)
3772 {
3773 STAFString errMsg = "Error on " + fromOptionName + ": " +
3774 fromEntry +
3775 "\n" + e.getText() + STAFString(": ") + e.getErrorCode();
3776
3777 return STAFServiceResult(kSTAFBaseOSError, errMsg);
3778 }
3779
3780 // If the FILE option is specified, verify that its value is a file
3781
3782 if (fileSpecified)
3783 {
3784 // Verify that the value of FILE is a file
3785
3786 if (entry->type() != kSTAFFSFile)
3787 {
3788 return STAFServiceResult(
3789 kSTAFInvalidValue,
3790 "'" + fromEntry + "' is not a File");
3791 }
3792 }
3793 else
3794 {
3795 // Verify that the value of DIRECTORY is a directory
3796
3797 if (entry->type() != kSTAFFSDirectory)
3798 {
3799 return STAFServiceResult(
3800 kSTAFInvalidValue,
3801 "'" + fromEntry + "' is not a Directory");
3802 }
3803 }
3804
3805 }
3806
3807 // Resolve the value specified for the "TO" option
3808
3809 STAFString toOptionName;
3810
3811 if (fileSpecified)
3812 {
3813 if (parsedResult->optionTimes("TOFILE") != 0)
3814 toOptionName = "TOFILE";
3815 else
3816 toOptionName = "TODIRECTORY";
3817 }
3818 else
3819 {
3820 toOptionName = "TODIRECTORY";
3821 }
3822
3823 STAFString toEntry;
3824
3825 rc = RESOLVE_STRING_OPTION(toOptionName, toEntry);
3826
3827 if (rc) return STAFServiceResult(rc, errorBuffer);
3828
3829 if ((fromOptionName == "FILE") && (toOptionName == "TOFILE"))
3830 {
3831 // When moving from a file to a file, if the TOFILE already exists,
3832 // verify that TOFILE is a file
3833
3834 STAFFSPath toEntryPath(toEntry);
3835 STAFFSEntryPtr entry;
3836
3837 try
3838 {
3839 if (toEntryPath.exists())
3840 {
3841 // Verify that it is a file
3842
3843 entry = toEntryPath.getEntry();
3844
3845 // Convert the toDir to the full long path name (e.g. with
3846 // correct file separators, correct case if Windows, no
3847 // unnecessary trailing slashes, etc)
3848
3849 toEntry = entry->path().asString();
3850
3851 // Verify that the value of FILE is a file
3852
3853 if (entry->type() != kSTAFFSFile)
3854 {
3855 return STAFServiceResult(
3856 kSTAFInvalidValue, "'" + toEntry + "' is not a File");
3857 }
3858 }
3859 }
3860 catch (STAFBaseOSErrorException &e)
3861 {
3862 result = "Error on " + toOptionName + ": " + toEntry +
3863 "\n" + e.getText() + STAFString(": ") + e.getErrorCode();
3864
3865 return STAFServiceResult(kSTAFBaseOSError, result);
3866 }
3867 }
3868 else if ((fromOptionName == "FILE") && (toOptionName == "TODIRECTORY"))
3869 {
3870 // Moving from a file to a directory.
3871 // Verify that TODIRECTORY is an existing directory
3872
3873 STAFFSPath toDirPath(toEntry);
3874 STAFFSEntryPtr entry;
3875
3876 try
3877 {
3878 if (!toDirPath.exists())
3879 {
3880 return STAFServiceResult(
3881 kSTAFDoesNotExist,
3882 toOptionName + " '" + toEntry + "' does not exist");
3883 }
3884
3885 entry = toDirPath.getEntry();
3886
3887 // Convert the toDir to the full long path name
3888 // (e.g. with correct file separators, correct case if Windows,
3889 // no unnecessary trailing slashes, etc)
3890
3891 toEntry = entry->path().asString();
3892
3893 // If the value of TODIRECTORY is not a directory, return
3894 // an error
3895
3896 if (entry->type() != kSTAFFSDirectory)
3897 {
3898 result = "'" + toEntry + "' is not a Directory";
3899 return STAFServiceResult(kSTAFInvalidValue, result);
3900 }
3901 }
3902 catch (STAFBaseOSErrorException &e)
3903 {
3904 result = "Error on " + toOptionName + ": " + toEntry +
3905 "\n" + e.getText() + STAFString(": ") + e.getErrorCode();
3906
3907 return STAFServiceResult(kSTAFBaseOSError, result);
3908 }
3909 }
3910 else if ((fromOptionName == "DIRECTORY") &&
3911 (toOptionName == "TODIRECTORY"))
3912 {
3913 // When moving from a directory to a directory, if the TODIRECTORY
3914 // already exists, verify that TODIRECTORY is a directory
3915
3916 STAFFSPath toEntryPath(toEntry);
3917 STAFFSEntryPtr entry;
3918
3919 try
3920 {
3921 if (toEntryPath.exists())
3922 {
3923 // Verify that it is a directory
3924
3925 entry = toEntryPath.getEntry();
3926
3927 // Convert the toDir to the full long path name (e.g. with
3928 // correct file separators, correct case if Windows, no
3929 // unnecessary trailing slashes, etc)
3930
3931 toEntry = entry->path().asString();
3932
3933 // If the value of TODIRECTORY is not a directory, return
3934 // an error
3935
3936 if (entry->type() != kSTAFFSDirectory)
3937 {
3938 result = "'" + toEntry + "' is not a Directory";
3939 return STAFServiceResult(kSTAFInvalidValue, result);
3940 }
3941 }
3942 }
3943 catch (STAFBaseOSErrorException &e)
3944 {
3945 result = "Error on " + toOptionName + ": " + toEntry +
3946 "\n" + e.getText() + STAFString(": ") + e.getErrorCode();
3947
3948 return STAFServiceResult(kSTAFBaseOSError, result);
3949 }
3950 }
3951
3952 // To move a file/directory on the same machine, use a "move" command
3953 // for the operating system so that it is faster and file permissions are
3954 // retained
3955
3956 #ifdef STAF_OS_TYPE_WIN32
3957 STAFString moveCommand = "move /Y";
3958 bool checkForWildcards = false;
3959 #else
3960 STAFString moveCommand = "mv -f";
3961 bool checkForWildcards = true;
3962 #endif
3963
3964 // If the from/to entry names are not already surrounded in double quotes,
3965 // enclose them in double quotes if they contain one or more spaces
3966 // (because that's needed for the OS "move"/"mv" commands).
3967
3968 moveCommand += " " + quote(fromEntry, checkForWildcards) + " " +
3969 quote(toEntry, false);
3970
3971 // Use a local PROCESS START WAIT request to run the "move" comamnd
3972
3973 STAFString request = "START SHELL COMMAND " +
3974 STAFHandle::wrapData(moveCommand) +
3975 " RETURNSTDOUT STDERRTOSTDOUT WAIT";
3976
3977 STAFResultPtr res = gSTAFProcHandlePtr->submit(
3978 "local", "PROCESS", request);
3979
3980 if (res->rc != kSTAFOk)
3981 {
3982 // Should not have a problem submitting the PROCESS START request
3983 return STAFServiceResult(res->rc, res->result);
3984 }
3985
3986 // Check if the process RC is 0
3987
3988 if (res->resultObj->type() == kSTAFMapObject)
3989 {
3990 STAFString processRC = res->resultObj->get("rc")->asString();
3991
3992 if (processRC != "0")
3993 {
3994 rc = kSTAFMoveError;
3995 }
3996
3997 STAFObjectPtr fileList = res->resultObj->get("fileList");
3998
3999 if (fileList->type() == kSTAFListObject)
4000 {
4001 // Get stdout/stderr information to return in the result
4002
4003 for (STAFObjectIteratorPtr iter = fileList->iterate();
4004 iter->hasNext();)
4005 {
4006 STAFObjectPtr fileMap = iter->next();
4007
4008 if (fileMap->type() == kSTAFMapObject)
4009 {
4010 if (fileMap->get("rc")->asString() == "0")
4011 {
4012 result += fileMap->get("data")->asString().strip();
4013 }
4014 else
4015 {
4016 result += "Error getting stdout/stderr for " +
4017 moveCommand + ", rc=" +
4018 fileMap->get("rc")->asString();
4019 }
4020 }
4021 }
4022 }
4023 }
4024 else
4025 {
4026 // Should never happen
4027 rc = kSTAFMoveError;
4028 result += "Error accessing result from command: " + moveCommand;
4029 }
4030
4031 return STAFServiceResult(rc, result);
4032 }
4033
handleGet(const STAFServiceRequest & requestInfo)4034 STAFServiceResult STAFFSService::handleGet(
4035 const STAFServiceRequest &requestInfo)
4036 {
4037 // Parse the request
4038
4039 STAFCommandParseResultPtr parsedResult =
4040 fGetParser.parse(requestInfo.fRequest);
4041
4042 if (parsedResult->rc != kSTAFOk)
4043 {
4044 return STAFServiceResult(kSTAFInvalidRequestString,
4045 parsedResult->errorBuffer, 0);
4046 }
4047
4048 DEFINE_VAR_POOL_LIST(varPoolList, varPoolListSize, requestInfo);
4049 STAFRC_t rc = kSTAFOk;
4050 STAFString errorBuffer;
4051 STAFString result;
4052
4053 if (parsedResult->optionTimes("FILE") != 0)
4054 {
4055 // GET FILE request
4056
4057 // Verify that the requesting machine/user has at least trust level 4
4058
4059 IVALIDATE_TRUST(4, "GET FILE");
4060
4061 // Determine if Text or Binary
4062
4063 bool convertToText = true; // Defaults to text
4064
4065 if (parsedResult->optionTimes("BINARY") != 0) convertToText = false;
4066
4067 // Determine the format
4068
4069 STAFString format;
4070
4071 if (parsedResult->optionTimes("FORMAT") != 0)
4072 {
4073 // Resolve the value specified for the FORMAT option
4074
4075 STAFString unresFormat = parsedResult->optionValue("FORMAT");
4076
4077 rc = RESOLVE_STRING_OPTION("FORMAT", format);
4078
4079 if (rc) return STAFServiceResult(rc, errorBuffer);
4080
4081 // If Binary, verify that the format specified is Hex
4082
4083 if (!convertToText && format.toUpperCase() != "HEX")
4084 return STAFServiceResult(kSTAFInvalidValue, format);
4085 }
4086 else
4087 {
4088 if (convertToText)
4089 format = "NATIVE"; // Default Text format is Native
4090 else
4091 format = "HEX"; // Default Binary format is Hex
4092 }
4093
4094 // Check if the undocumented TEST option was specified
4095
4096 bool testFlag = false;
4097
4098 if (parsedResult->optionTimes("TEST") != 0)
4099 testFlag = true;
4100
4101 // Resolve the value specified for FILE
4102
4103 STAFString file;
4104
4105 rc = RESOLVE_STRING_OPTION("FILE", file);
4106
4107 if (rc) return STAFServiceResult(rc, errorBuffer);
4108
4109 // Check if the file exists
4110
4111 STAFFSPath path(file);
4112
4113 try
4114 {
4115 if (!path.exists())
4116 return STAFServiceResult(
4117 kSTAFDoesNotExist, "File " + file + " does not exist");
4118 }
4119 catch (STAFBaseOSErrorException &e)
4120 {
4121 STAFString errMsg = "Error on file: " + file + "\n" +
4122 e.getText() + STAFString(": ") + e.getErrorCode();
4123
4124 return STAFServiceResult(kSTAFBaseOSError, errMsg);
4125 }
4126
4127 // Get the actual path name and remove any unnecessary trailing slashes
4128 file = path.setRoot(path.root()).asString();
4129
4130 // Open the file to read it
4131
4132 fstream inFile(file.toCurrentCodePage()->buffer(),
4133 ios::in | STAF_ios_binary);
4134
4135 if (!inFile)
4136 return STAFServiceResult(kSTAFFileOpenError, file);
4137
4138 // Get the size of the file (upperSize and lowerSize).
4139 // If the file size is < 4G, upperSize will be zero.
4140
4141 STAFFSEntryPtr entry;
4142
4143 try
4144 {
4145 entry = path.getEntry();
4146 }
4147 catch (STAFBaseOSErrorException &e)
4148 {
4149 STAFString errMsg = "Error on file: " + file + "\n" +
4150 e.getText() + STAFString(": ") + e.getErrorCode();
4151
4152 return STAFServiceResult(kSTAFBaseOSError, errMsg);
4153 }
4154
4155 unsigned int upperSize = entry->size().first;
4156 unsigned int lowerSize = entry->size().second;
4157
4158 // Check if file size exceeds the maximum that the FS service handles
4159
4160 if (upperSize > 0)
4161 {
4162 STAFString errMsg = STAFString(
4163 "File size exceeds the maximum size (") + UINT_MAX +
4164 ") supported. File name: " + file;
4165 return STAFServiceResult(kSTAFFileReadError, errMsg);
4166 }
4167
4168 unsigned int fileLength = lowerSize;
4169
4170 // Added for debugging memory issues
4171
4172 if (gResultWarningSize)
4173 {
4174 if (fileLength > gResultWarningSize)
4175 {
4176 // Log a warning tracepoint message
4177
4178 STAFString warningMsg = STAFString(
4179 "WARNING: Submitting a FS GET FILE request for a large "
4180 "file (") + fileLength + " bytes) uses a lot of memory. "
4181 "STAFFSService::handleGet()";
4182
4183 warningMsg += " - Client: " + requestInfo.fMachine +
4184 ", Handle: " + STAFString(requestInfo.fHandle) +
4185 ", Handle Name: " + requestInfo.fHandleName +
4186 ", Request: " + requestInfo.fRequest;
4187
4188 STAFTrace::trace(kSTAFTraceWarning, warningMsg);
4189 }
4190 }
4191
4192 // Determine the maximum return file size
4193
4194 unsigned int maxFileSize = gMaxReturnFileSize; // Default
4195
4196 // Check if variable STAF/MaxReturnFileSize was set to a non-zero
4197 // value. Resolve this variable using only the originating handle's
4198 // pool associated with this request so create a variable pool that
4199 // only contains the request variable pool.
4200
4201 const STAFVariablePool *theVarPoolList[] =
4202 {
4203 requestInfo.fRequestVarPool
4204 };
4205
4206 unsigned int theVarPoolListSize = sizeof(theVarPoolList) /
4207 sizeof(const STAFVariablePool *);
4208
4209 STAFString sizeString;
4210
4211 STAFRC_t maxSizeRC = STAFVariablePool::resolve(
4212 "{STAF/MaxReturnFileSize}",
4213 theVarPoolList, theVarPoolListSize, sizeString);
4214
4215 if (maxSizeRC == kSTAFOk)
4216 {
4217 // Variable STAF/MaxReturnFileSize exists
4218
4219 // Verify if its size value is valid and convert it to bytes
4220 // if needed
4221
4222 STAFString_t errorBuffer = 0;
4223 unsigned int maxSize = 0; // 0 means no size limit
4224
4225 STAFRC_t rc = STAFUtilConvertSizeString(
4226 sizeString.getImpl(), &maxSize, &errorBuffer);
4227
4228 if (rc != kSTAFOk)
4229 {
4230 STAFString errMsg = STAFString(
4231 "Variable STAF/MaxReturnFileSize in the originating "
4232 "handle's variable pool for this request is set to "
4233 "an invalid value: ") + sizeString + " \n" +
4234 STAFString(errorBuffer, STAFString::kShallow);
4235
4236 return STAFServiceResult(kSTAFInvalidValue, errMsg);
4237 }
4238
4239 if (maxSize != 0)
4240 {
4241 if ((gMaxReturnFileSize == 0) ||
4242 (maxSize < gMaxReturnFileSize))
4243 {
4244 // Assign the maximum file size based on the
4245 // STAF/MaxReturnFileSize variable
4246 maxFileSize = maxSize;
4247 }
4248 }
4249 }
4250
4251 // Determine if the file size exceeds the maximum allowed size
4252
4253 if ((maxFileSize != 0) && (fileLength > maxFileSize))
4254 {
4255 return STAFServiceResult(
4256 kSTAFMaximumSizeExceeded,
4257 STAFString("File '") + file + "' size is " + fileLength +
4258 " bytes which exceeds " + STAFString(maxFileSize) +
4259 " bytes, the maximum return file size allowed");
4260 }
4261
4262 // Initialize the output buffer and read in the file
4263
4264 STAFBuffer<char> buffer(new char[fileLength], STAFBuffer<char>::INIT,
4265 STAFBuffer<char>::ARRAY);
4266
4267 inFile.read(buffer, fileLength);
4268 inFile.close();
4269
4270 if (!convertToText)
4271 {
4272 // Convert the file contents to a hex format
4273 return convertToHex(buffer, fileLength);
4274 }
4275
4276 // Don't convert line-endings in the text file if format is "AsIs"
4277
4278 if (format.toUpperCase() == "ASIS")
4279 {
4280 // If the undocumented TEST option was specified.
4281
4282 if (testFlag)
4283 {
4284 // Return the result in hex to verify that the line-ending
4285 // characters were not converted.
4286 return convertToHex(buffer, fileLength);
4287 }
4288
4289 return STAFServiceResult(rc, STAFString(buffer, fileLength));
4290 }
4291
4292 // Convert the line ending characters in the text file
4293
4294 return convertLineEndings(buffer, fileLength, format,
4295 requestInfo.fEndpoint,
4296 requestInfo.fIsLocalRequest, testFlag);
4297 }
4298 else
4299 {
4300 // GET ENTRY request
4301
4302 // Verify that the requesting machine/user has at least trust level 2
4303
4304 IVALIDATE_TRUST(2, "GET ENTRY");
4305
4306 STAFString entryName;
4307
4308 rc = RESOLVE_STRING_OPTION("ENTRY", entryName);
4309
4310 if (rc) return STAFServiceResult(rc, errorBuffer);
4311
4312 STAFFSPath path(entryName);
4313
4314 try
4315 {
4316 if (!path.exists())
4317 {
4318 return STAFServiceResult(
4319 kSTAFDoesNotExist, "Entry " + entryName +
4320 " does not exist");
4321 }
4322 }
4323 catch (STAFBaseOSErrorException &e)
4324 {
4325 STAFString errMsg = "Error on entry: " + entryName + "\n" +
4326 e.getText() + STAFString(": ") + e.getErrorCode();
4327
4328 return STAFServiceResult(kSTAFBaseOSError, errMsg);
4329 }
4330
4331 STAFFSEntryPtr entry;
4332
4333 try
4334 {
4335 entry = path.getEntry();
4336 }
4337 catch (STAFBaseOSErrorException &e)
4338 {
4339 STAFString errMsg = e.getText() + STAFString(": ") +
4340 e.getErrorCode();
4341
4342 return STAFServiceResult(kSTAFBaseOSError, errMsg);
4343 }
4344
4345 if (parsedResult->optionTimes("TYPE") != 0)
4346 {
4347 result = getTypeString(entry->type());
4348 }
4349 else if (parsedResult->optionTimes("SIZE") != 0)
4350 {
4351 // Create a marshalled map containing entry size information
4352
4353 STAFObjectPtr mc = STAFObject::createMarshallingContext();
4354 mc->setMapClassDefinition(fEntrySizeInfoClass->reference());
4355
4356 STAFObjectPtr entrySizeMap = fEntrySizeInfoClass->createInstance();
4357 entrySizeMap->put("size", STAFString(entry->size64()));
4358 entrySizeMap->put("upperSize", STAFString(entry->size().first));
4359 entrySizeMap->put("lowerSize", STAFString(entry->size().second));
4360
4361 mc->setRootObject(entrySizeMap);
4362 result = mc->marshall();
4363 }
4364 else if (parsedResult->optionTimes("MODTIME") != 0)
4365 {
4366 result = entry->modTime().asString();
4367 }
4368 else if (parsedResult->optionTimes("LINKTARGET") != 0)
4369 {
4370 if (entry->linkTarget() != "")
4371 result = entry->linkTarget();
4372 else
4373 result = sNoneString;
4374 }
4375 else if (parsedResult->optionTimes("CHECKSUM") != 0)
4376 {
4377 #ifdef STAF_USE_SSL
4378
4379 // Check if the entry specified is a directory and if so, return
4380 // an error as you cannot get the checksum for a directory
4381
4382 if (entry->type() == kSTAFFSDirectory)
4383 {
4384 return STAFServiceResult(
4385 kSTAFInvalidValue,
4386 "Cannot get the checksum for an entry that is a "
4387 "directory");
4388 }
4389
4390 // Default the checksum alogrithm to MD5 if not specified
4391
4392 STAFString checksumAlgorithm = "MD5";
4393
4394 // Get the checksum value, if specified, and resolve any STAF
4395 // variables in it
4396
4397 if (parsedResult->optionValue("CHECKSUM") != "")
4398 {
4399 rc = RESOLVE_OPTIONAL_STRING_OPTION(
4400 "CHECKSUM", checksumAlgorithm);
4401 }
4402
4403 // Compute the checksum for the specified cryptographic hashing
4404 // algorithm (aka digest) using functions provided by OpenSSL
4405
4406 const EVP_MD *md;
4407
4408 OpenSSL_add_all_digests();
4409
4410 md = EVP_get_digestbyname(
4411 checksumAlgorithm.toUpperCase().toCurrentCodePage()->buffer());
4412
4413 if (!md)
4414 {
4415 return STAFServiceResult(
4416 kSTAFInvalidValue,
4417 STAFString("Unknown algorithm specified for the "
4418 "CHECKSUM option: ") + checksumAlgorithm);
4419 }
4420
4421 // Open the file to read it
4422
4423 fstream inFile(entryName.toCurrentCodePage()->buffer(),
4424 ios::in | STAF_ios_binary);
4425
4426 if (!inFile)
4427 {
4428 return STAFServiceResult(
4429 kSTAFFileOpenError,
4430 STAFString("Cannot open file ") + entryName);
4431 }
4432
4433 // Get the size of the file (upperSize and lowerSize).
4434 // If the file size is < 4G, upperSize will be zero.
4435
4436 unsigned int upperSize = entry->size().first;
4437 unsigned int lowerSize = entry->size().second;
4438
4439 // Check if file size exceeds the maximum that the FS service handles
4440
4441 if (upperSize > 0)
4442 {
4443 inFile.close();
4444
4445 STAFString errMsg = STAFString(
4446 "File size exceeds the maximum size (") + UINT_MAX +
4447 ") supported. File name: " + entryName;
4448
4449 return STAFServiceResult(kSTAFFileReadError, errMsg);
4450 }
4451
4452 unsigned int fileLength = lowerSize;
4453
4454 EVP_MD_CTX* mdctx = EVP_MD_CTX_create();
4455 unsigned char md_value[EVP_MAX_MD_SIZE];
4456 unsigned int md_len;
4457
4458 EVP_DigestInit_ex(mdctx, md, NULL);
4459
4460 // Read the entire file using a buffer size of 4096 bytes and
4461 // update the digest with the buffer
4462
4463 unsigned int bytesCopied = 0;
4464 char fileBuffer[4096] = {0};
4465 unsigned int writeLength = 0;
4466
4467 while ((fileLength > 0) && inFile.good())
4468 {
4469 writeLength = STAF_MIN(sizeof(fileBuffer), fileLength);
4470
4471 rc = readFile(inFile, reinterpret_cast<char *>(fileBuffer),
4472 writeLength, entryName, "local", fileLength,
4473 bytesCopied);
4474
4475 if (rc != kSTAFOk) break;
4476
4477 EVP_DigestUpdate(mdctx, fileBuffer, writeLength);
4478 fileLength -= writeLength;
4479 bytesCopied += writeLength;
4480 }
4481
4482 inFile.close();
4483
4484 if (rc == kSTAFOk)
4485 {
4486 // Get the checksum value
4487 EVP_DigestFinal_ex(mdctx, md_value, &md_len);
4488 }
4489
4490 EVP_MD_CTX_destroy(mdctx);
4491
4492 if (rc == kSTAFOk)
4493 {
4494 // Convert the checksum value to a hexadecimal format
4495 return convertToHex(reinterpret_cast<char *>(md_value), md_len);
4496 }
4497 else
4498 {
4499 return STAFServiceResult(
4500 kSTAFFileReadError,
4501 STAFString("Error reading file ") + entryName);
4502 }
4503 #else
4504 return STAFServiceResult(
4505 kSTAFInvalidRequestString, "Cannot specify the CHECKSUM "
4506 "option because STAF OpenSSL support is not provided");
4507 #endif
4508 }
4509
4510 return STAFServiceResult(rc, result);
4511 }
4512 }
4513
4514
handleList(const STAFServiceRequest & requestInfo)4515 STAFServiceResult STAFFSService::handleList(
4516 const STAFServiceRequest &requestInfo)
4517 {
4518 // Verify that the requesting machine/user has at least trust level 2
4519
4520 IVALIDATE_TRUST(2, "LIST");
4521
4522 // Parse the request
4523
4524 STAFCommandParseResultPtr parsedResult =
4525 fListParser.parse(requestInfo.fRequest);
4526
4527 if (parsedResult->rc != kSTAFOk)
4528 {
4529 return STAFServiceResult(kSTAFInvalidRequestString,
4530 parsedResult->errorBuffer, 0);
4531 }
4532
4533 DEFINE_VAR_POOL_LIST(varPoolList, varPoolListSize, requestInfo);
4534 STAFString errorBuffer;
4535
4536 if (parsedResult->optionTimes("SETTINGS") > 0)
4537 {
4538 // LIST SETTINGS
4539
4540 // Create a marshalling context to represent the settings info
4541
4542 STAFObjectPtr mc = STAFObject::createMarshallingContext();
4543 mc->setMapClassDefinition(fSettingsClass->reference());
4544 STAFObjectPtr settingsMap = fSettingsClass->createInstance();
4545
4546 if (gStrictFSCopyTrust)
4547 settingsMap->put("strictFSCopyTrust", "Enabled");
4548 else
4549 settingsMap->put("strictFSCopyTrust", "Disabled");
4550
4551 mc->setRootObject(settingsMap);
4552
4553 return STAFServiceResult(kSTAFOk, mc->marshall());
4554 }
4555
4556 //LIST DIRECTORY <Name> [RECURSE] [LONG [DETAILS] | SUMMARY] [TYPE <Types>]
4557 // [NAME <Pattern>] [EXT <Pattern>] [CASESENSITIVE | CASEINSENSITIVE]
4558 // [SORTBYNAME | SORTBYSIZE | SORTBYMODTIME]
4559
4560 STAFFSSortBy_t sortBy = kSTAFFSNoSort;
4561 STAFFSCaseSensitive_t caseSensitive = kSTAFFSCaseDefault;
4562 unsigned int entryTypesUInt = kSTAFFSNormal;
4563 bool showLong = (parsedResult->optionTimes("LONG") > 0);
4564 bool details = (parsedResult->optionTimes("DETAILS") > 0);
4565 bool summary = (parsedResult->optionTimes("SUMMARY") > 0);
4566 bool recurse = (parsedResult->optionTimes("RECURSE") > 0);
4567
4568 STAFString namePattern(kUTF8_STAR);
4569 STAFString extPattern(kUTF8_STAR);
4570 STAFString dir;
4571 STAFString typeString;
4572 STAFRC_t rc = RESOLVE_STRING_OPTION("DIRECTORY", dir);
4573
4574 if (!rc) RESOLVE_OPTIONAL_STRING_OPTION("NAME", namePattern);
4575 if (!rc) RESOLVE_OPTIONAL_STRING_OPTION("EXT" , extPattern);
4576 if (!rc) RESOLVE_OPTIONAL_STRING_OPTION("TYPE", typeString);
4577
4578 if (rc) return STAFServiceResult(rc, errorBuffer);
4579
4580 if (parsedResult->optionTimes("SORTBYNAME") != 0)
4581 sortBy = kSTAFFSSortByName;
4582 else if (parsedResult->optionTimes("SORTBYSIZE") != 0)
4583 sortBy = kSTAFFSSortBySize;
4584 else if (parsedResult->optionTimes("SORTBYMODTIME") != 0)
4585 sortBy = kSTAFFSSortByModTime;
4586
4587 if (parsedResult->optionTimes("CASESENSITIVE") != 0)
4588 caseSensitive = kSTAFFSCaseSensitive;
4589 else if (parsedResult->optionTimes("CASEINSENSITIVE") != 0)
4590 caseSensitive = kSTAFFSCaseInsensitive;
4591
4592 if (typeString.toUpperCase() == "ALL")
4593 entryTypesUInt = kSTAFFSAll;
4594 else if (typeString.length() != 0)
4595 entryTypesUInt = getTypeMaskFromString(typeString, true);
4596
4597 STAFFSPath dirPath(dir);
4598
4599 try
4600 {
4601 if (!dirPath.exists())
4602 return STAFServiceResult(
4603 kSTAFDoesNotExist, "Directory " + dir + " does not exist");
4604 }
4605 catch (STAFBaseOSErrorException &e)
4606 {
4607 STAFString errMsg = "Error on Directory: " + dir + "\n" +
4608 e.getText() + STAFString(": ") + e.getErrorCode();
4609
4610 return STAFServiceResult(kSTAFBaseOSError, errMsg);
4611 }
4612
4613 // Create a marshalled list of maps containing file information
4614
4615 STAFObjectPtr mc = STAFObject::createMarshallingContext();
4616
4617 if (showLong && details)
4618 mc->setMapClassDefinition(fListDetailsInfoClass->reference());
4619 else if (showLong && !details)
4620 mc->setMapClassDefinition(fListLongInfoClass->reference());
4621 else if (summary)
4622 mc->setMapClassDefinition(fListSummaryInfoClass->reference());
4623
4624 STAFFSEntryPtr dirPathEntry;
4625
4626 try
4627 {
4628 dirPathEntry = dirPath.getEntry();
4629 }
4630 catch (STAFBaseOSErrorException &e)
4631 {
4632 STAFString errMsg = e.getText() + STAFString(": ") + e.getErrorCode();
4633
4634 return STAFServiceResult(kSTAFBaseOSError, errMsg);
4635 }
4636
4637 // Return an error if the DIRECTORY specified is not a directory
4638
4639 if (dirPathEntry->type() != kSTAFFSDirectory)
4640 {
4641 return STAFServiceResult(
4642 kSTAFInvalidValue, dir + " is not a directory");
4643 }
4644
4645 if (summary)
4646 {
4647 // Get a summary of the statistics for the directory such as
4648 // total size, number of files in the directory, and number of
4649 // subdirectories
4650
4651 STAFObjectPtr summaryMap = fListSummaryInfoClass->createInstance();
4652
4653 STAFUInt64_t dirSize = 0;
4654 STAFUInt64_t numFiles = 0;
4655 STAFUInt64_t numDirectories = 0;
4656
4657 getDirectorySize(dirPathEntry, namePattern, extPattern,
4658 entryTypesUInt, caseSensitive, recurse,
4659 dirSize, numFiles, numDirectories);
4660
4661 summaryMap->put("name", dirPathEntry->path().asString());
4662 summaryMap->put("size", STAFString(dirSize));
4663 summaryMap->put("numFiles", STAFString(numFiles));
4664 summaryMap->put("numDirectories", STAFString(numDirectories));
4665
4666 mc->setRootObject(summaryMap);
4667
4668 return STAFServiceResult(kSTAFOk, mc->marshall());
4669 }
4670
4671 STAFObjectPtr outputList = STAFObject::createList();
4672
4673 // Get the actual directory path name
4674
4675 STAFString rootDir = dirPath.setRoot(dirPath.root()).asString();
4676
4677 #ifdef STAF_OS_TYPE_WIN32
4678
4679 // On Windows, need to remove the trailing backslash from a path that
4680 // is a root directory like C:\
4681
4682 if (rootDir.findFirstNotOf(kUTF8_BSLASH) != STAFString::kNPos)
4683 {
4684 unsigned int lastNonSlashLoc = rootDir.findLastNotOf(kUTF8_BSLASH);
4685
4686 if (lastNonSlashLoc + 1 != rootDir.length())
4687 {
4688 rootDir = rootDir.subString(
4689 0, lastNonSlashLoc + 1, STAFString::kChar);
4690 }
4691 }
4692 #endif
4693
4694 if (!recurse)
4695 {
4696 // List matching entries non-recursively (e.g. don't check
4697 // sub-directories for any matching entries)
4698
4699 // Get a list of all matching entries
4700
4701 STAFFSEnumPtr dirEnum = dirPathEntry->enumerate(
4702 namePattern, extPattern, STAFFSEntryType_t(entryTypesUInt),
4703 sortBy, caseSensitive);
4704
4705 // Iterate through the sorted matching entries and format each entry
4706
4707 for (; dirEnum->isValid(); dirEnum->next())
4708 {
4709 addListDirectoryEntry(rootDir, dirEnum->entry(),
4710 outputList, mc, showLong, details);
4711 }
4712 }
4713 else
4714 {
4715 // List matching entries recursively (e.g. check sub-directories for
4716 // any matching entries as well)
4717
4718 // Get a list of all matching entries
4719
4720 STAFFSEntryList entryList;
4721
4722 recurseListDir(dirPathEntry, namePattern, extPattern,
4723 entryTypesUInt, caseSensitive, sortBy, entryList);
4724
4725 // Sort the entries by name in the specified case, or by size, or by
4726 // last modification time.
4727
4728 switch (sortBy)
4729 {
4730 case kSTAFFSSortByName:
4731 {
4732 std::sort(entryList.begin(), entryList.end(),
4733 STAFSortEnumByName(caseSensitive));
4734 break;
4735 }
4736
4737 case kSTAFFSSortBySize:
4738 {
4739 std::sort(entryList.begin(), entryList.end(),
4740 sortEnumBySize);
4741 break;
4742 }
4743
4744 case kSTAFFSSortByModTime:
4745 {
4746 std::sort(entryList.begin(), entryList.end(),
4747 sortEnumByModTime);
4748 break;
4749 }
4750
4751 default: break;
4752 }
4753
4754 // Iterate through the sorted matching entries and format each entry
4755
4756 for (STAFFSEntryList::iterator iter = entryList.begin();
4757 iter != entryList.end(); ++iter)
4758 {
4759 addListDirectoryEntry(rootDir, *iter, outputList, mc,
4760 showLong, details);
4761 }
4762 }
4763
4764 mc->setRootObject(outputList);
4765
4766 return STAFServiceResult(kSTAFOk, mc->marshall());
4767 }
4768
4769
handleListCopyRequests(const STAFServiceRequest & requestInfo)4770 STAFServiceResult STAFFSService::handleListCopyRequests(
4771 const STAFServiceRequest &requestInfo)
4772 {
4773 // Verify that the requesting machine/user has at least trust level 2
4774
4775 IVALIDATE_TRUST(2, "LIST");
4776
4777 // Parse the request
4778
4779 STAFCommandParseResultPtr parsedResult = fListCopyRequestsParser.parse(
4780 requestInfo.fRequest);
4781
4782 if (parsedResult->rc != kSTAFOk)
4783 {
4784 return STAFServiceResult(kSTAFInvalidRequestString,
4785 parsedResult->errorBuffer, 0);
4786 }
4787
4788 DEFINE_VAR_POOL_LIST(varPoolList, varPoolListSize, requestInfo);
4789 STAFString errorBuffer;
4790
4791 // LIST COPYREQUESTS request
4792
4793 // Create a marshalling context to represent the list of copy requests
4794
4795 STAFObjectPtr mc = STAFObject::createMarshallingContext();
4796
4797 bool longFlag = false;
4798 bool toFlag = false;
4799 bool fromFlag = false;
4800 bool fileFlag = false;
4801 bool directoryFlag = false;
4802 bool binaryFlag = false;
4803 bool textFlag = false;
4804
4805 if (parsedResult->optionTimes("LONG") > 0) longFlag = true;
4806 if (parsedResult->optionTimes("INBOUND") > 0) toFlag = true;
4807 if (parsedResult->optionTimes("OUTBOUND") > 0) fromFlag = true;
4808 if (parsedResult->optionTimes("DIRECTORY") > 0) directoryFlag = true;
4809
4810 if (parsedResult->optionTimes("FILE") > 0)
4811 {
4812 fileFlag = true;
4813
4814 if (parsedResult->optionTimes("BINARY") > 0) binaryFlag = true;
4815 if (parsedResult->optionTimes("TEXT") > 0) textFlag = true;
4816 }
4817
4818 if (!toFlag && !fromFlag)
4819 {
4820 toFlag = true;
4821 fromFlag = true;
4822 }
4823
4824 if (!fileFlag && !directoryFlag)
4825 {
4826 fileFlag = true;
4827 directoryFlag = true;
4828 }
4829
4830 if (!binaryFlag && !textFlag)
4831 {
4832 binaryFlag = true;
4833 textFlag = true;
4834 }
4835
4836 if (!longFlag)
4837 {
4838 mc->setMapClassDefinition(fCopyRequestClass->reference());
4839 }
4840 else
4841 {
4842 mc->setMapClassDefinition(fCopyFileClass->reference());
4843 mc->setMapClassDefinition(fFileCopyStateClass->reference());
4844 mc->setMapClassDefinition(fCopyDirectoryClass->reference());
4845 mc->setMapClassDefinition(fDirectoryCopyStateClass->reference());
4846 }
4847
4848 STAFObjectPtr resultList = STAFObject::createList();
4849
4850 // Read FS Copy Map
4851
4852 STAFFSCopyManager::FSCopyMap copyMap = gFSCopyManagerPtr->
4853 getFSCopyMapCopy();
4854
4855 STAFFSCopyManager::FSCopyMap::iterator iter;
4856
4857 for (iter = copyMap.begin(); iter != copyMap.end(); ++iter)
4858 {
4859 STAFFSCopyManager::FSCopyDataPtr copyData = iter->second;
4860
4861 STAFObjectPtr resultMap;
4862
4863 if (!longFlag)
4864 resultMap = fCopyRequestClass->createInstance();
4865 else if (copyData->type == kSTAFFSFileCopy)
4866 resultMap = fCopyFileClass->createInstance();
4867 else
4868 resultMap = fCopyDirectoryClass->createInstance();
4869
4870 if (copyData->direction == kSTAFFSCopyFrom)
4871 {
4872 if (!fromFlag) continue;
4873
4874 resultMap->put("io", "Out");
4875 }
4876 else
4877 {
4878 if (!toFlag) continue;
4879
4880 resultMap->put("io", "In");
4881 }
4882
4883 if (copyData->type == kSTAFFSFileCopy)
4884 {
4885 if (!fileFlag) continue;
4886
4887 resultMap->put("type", "F");
4888 }
4889 else
4890 {
4891 if (!directoryFlag) continue;
4892
4893 resultMap->put("type", "D");
4894 }
4895
4896 resultMap->put("startTimestamp", copyData->startTimestamp);
4897 resultMap->put("machine", copyData->machine);
4898 resultMap->put("name", copyData->name);
4899
4900 if (longFlag)
4901 {
4902 // Assign additional information for the copy in progress
4903
4904 if (copyData->type == kSTAFFSFileCopy)
4905 {
4906 if (copyData->mode == kSTAFFSBinary)
4907 {
4908 if (!binaryFlag) continue;
4909
4910 resultMap->put("mode", "Binary");
4911 }
4912 else
4913 {
4914 if (!textFlag) continue;
4915
4916 resultMap->put("mode", "Text");
4917 }
4918
4919 STAFObjectPtr stateMap = fFileCopyStateClass->
4920 createInstance();
4921
4922 if (copyData->fileSize != 0)
4923 {
4924 stateMap->put("fileSize", copyData->fileSize);
4925 }
4926
4927 stateMap->put("bytesCopied", copyData->bytesCopied);
4928
4929 resultMap->put("state", stateMap);
4930 }
4931 else
4932 {
4933 STAFObjectPtr stateMap;
4934
4935 stateMap = fDirectoryCopyStateClass->createInstance();
4936
4937 if (copyData->mode == kSTAFFSBinary)
4938 {
4939 stateMap->put("mode", "Binary");
4940 }
4941 else
4942 {
4943 stateMap->put("mode", "Text");
4944 }
4945
4946 if (copyData->entryName != STAFString(""))
4947 {
4948 stateMap->put("name", copyData->entryName);
4949
4950 if (copyData->fileSize != 0)
4951 {
4952 stateMap->put("fileSize", copyData->fileSize);
4953 }
4954
4955 stateMap->put("bytesCopied", copyData->bytesCopied);
4956 }
4957
4958 resultMap->put("state", stateMap);
4959 }
4960 }
4961
4962 resultList->append(resultMap);
4963 }
4964
4965 mc->setRootObject(resultList);
4966
4967 return STAFServiceResult(kSTAFOk, mc->marshall());
4968 }
4969
4970
handleCreate(const STAFServiceRequest & requestInfo)4971 STAFServiceResult STAFFSService::handleCreate(
4972 const STAFServiceRequest &requestInfo)
4973 {
4974 // Verify that the requesting machine/user has at least trust level 4
4975
4976 IVALIDATE_TRUST(4, "CREATE");
4977
4978 // Parse the request
4979
4980 STAFCommandParseResultPtr parsedResult =
4981 fCreateParser.parse(requestInfo.fRequest);
4982
4983 if (parsedResult->rc != kSTAFOk)
4984 {
4985 return STAFServiceResult(kSTAFInvalidRequestString,
4986 parsedResult->errorBuffer, 0);
4987 }
4988
4989 DEFINE_VAR_POOL_LIST(varPoolList, varPoolListSize, requestInfo);
4990 unsigned int osRC = 0;
4991 STAFFSDirectoryCreateMode_t createMode = kSTAFFSCreateDirOnly;
4992 STAFString dir;
4993 STAFString result;
4994 STAFString errorBuffer;
4995 STAFRC_t rc = RESOLVE_STRING_OPTION("DIRECTORY", dir);
4996
4997 if (rc) return STAFServiceResult(rc, errorBuffer);
4998
4999 if (parsedResult->optionTimes("FULLPATH") != 0)
5000 createMode = kSTAFFSCreatePath;
5001
5002 rc = STAFFSCreateDirectory(dir.getImpl(), createMode, &osRC);
5003
5004 if (rc == kSTAFBaseOSError)
5005 {
5006 result = STAFString("Could not create directory ") + dir +
5007 STAFString(", OS RC: ") + osRC;
5008 }
5009 else if (rc == kSTAFAlreadyExists)
5010 {
5011 if (parsedResult->optionTimes("FAILIFEXISTS") != 0)
5012 {
5013 result = dir;
5014 }
5015 else
5016 {
5017 // The entry specified for the DIRECTORY option already exists.
5018 // If the entry specified is a directory then don't return an
5019 // error since the FAILIFEXISTS option wan't specified.
5020 // However, if it's not a directory, return an error.
5021
5022 STAFFSPath dirPath(dir);
5023 STAFFSEntryPtr dirPathEntry;
5024
5025 try
5026 {
5027 dirPathEntry = dirPath.getEntry();
5028
5029 if (dirPathEntry->type() == kSTAFFSDirectory)
5030 rc = kSTAFOk; // Not an error
5031 else
5032 result = dir + " already exists, but is not a directory";
5033 }
5034 catch (STAFBaseOSErrorException)
5035 {
5036 rc = kSTAFOk; // Ignore exceptions
5037 }
5038 }
5039 }
5040
5041 return STAFServiceResult(rc, result);
5042 }
5043
5044
handleDelete(const STAFServiceRequest & requestInfo)5045 STAFServiceResult STAFFSService::handleDelete(
5046 const STAFServiceRequest &requestInfo)
5047 {
5048 // Parse the request
5049
5050 STAFCommandParseResultPtr parsedResult = fDeleteParser.parse(
5051 requestInfo.fRequest);
5052
5053 if (parsedResult->rc != kSTAFOk)
5054 {
5055 return STAFServiceResult(kSTAFInvalidRequestString,
5056 parsedResult->errorBuffer, 0);
5057 }
5058
5059 DEFINE_VAR_POOL_LIST(varPoolList, varPoolListSize, requestInfo);
5060 bool children = (parsedResult->optionTimes("CHILDREN") > 0);
5061 bool recurse = (parsedResult->optionTimes("RECURSE") > 0);
5062 bool ignoreErrors = (parsedResult->optionTimes("IGNOREERRORS") > 0);
5063 STAFFSCaseSensitive_t caseSensitive = kSTAFFSCaseDefault;
5064 unsigned int entryTypesUInt = kSTAFFSAll & ~kSTAFFSSpecialDirectory;
5065 STAFString namePattern(kUTF8_STAR);
5066 STAFString extPattern(kUTF8_STAR);
5067 STAFString entryString;
5068 STAFString typeString;
5069 STAFString result;
5070 STAFString errorBuffer;
5071
5072 // Verify that the requesting machine/user has at least trust level 4
5073 // if RECURSE is not specified and trust level 5 if RECURSE is specified
5074
5075 if (!recurse)
5076 {
5077 IVALIDATE_TRUST(4, "DELETE");
5078 }
5079 else
5080 {
5081 IVALIDATE_TRUST(5, "DELETE RECURSE");
5082 }
5083
5084 STAFRC_t rc = RESOLVE_STRING_OPTION("ENTRY", entryString);
5085
5086 if (!rc) RESOLVE_OPTIONAL_STRING_OPTION("NAME", namePattern);
5087 if (!rc) RESOLVE_OPTIONAL_STRING_OPTION("EXT" , extPattern);
5088 if (!rc) RESOLVE_OPTIONAL_STRING_OPTION("TYPE", typeString);
5089
5090 if (rc) return STAFServiceResult(rc, errorBuffer);
5091
5092 if (parsedResult->optionTimes("CASESENSITIVE") != 0)
5093 caseSensitive = kSTAFFSCaseSensitive;
5094 else if (parsedResult->optionTimes("CASEINSENSITIVE") != 0)
5095 caseSensitive = kSTAFFSCaseInsensitive;
5096
5097 if (typeString.toUpperCase() == "ALL")
5098 entryTypesUInt = kSTAFFSAll & ~kSTAFFSSpecialDirectory;
5099 else if (typeString.length() != 0)
5100 entryTypesUInt = getTypeMaskFromString(typeString, false);
5101
5102 STAFFSPath entryPath(entryString);
5103
5104 try
5105 {
5106 if (!entryPath.exists())
5107 return STAFServiceResult(
5108 kSTAFDoesNotExist, "Entry " + entryString + " does not exist");
5109 }
5110 catch (STAFBaseOSErrorException &e)
5111 {
5112 STAFString errMsg = "Error on Entry: " + entryString + "\n" +
5113 e.getText() + STAFString(": ") + e.getErrorCode();
5114
5115 return STAFServiceResult(kSTAFBaseOSError, errMsg);
5116 }
5117
5118
5119 STAFFSEntryPtr entry;
5120
5121 try
5122 {
5123 entry = entryPath.getEntry();
5124 }
5125 catch (STAFBaseOSErrorException &e)
5126 {
5127 STAFString errMsg = e.getText() + STAFString(": ") +
5128 e.getErrorCode();
5129
5130 return STAFServiceResult(kSTAFBaseOSError, errMsg);
5131 }
5132
5133 unsigned int osRC = 0;
5134
5135 // Create a marshalled list of error information deleting a directory
5136
5137 STAFObjectPtr mc = STAFObject::createMarshallingContext();
5138 mc->setMapClassDefinition(fErrorInfoClass->reference());
5139 STAFObjectPtr outputList = STAFObject::createList();
5140
5141 if (recurse)
5142 {
5143 if (entry->type() == kSTAFFSDirectory)
5144 {
5145 recurseRemove(entry, namePattern, extPattern, entryTypesUInt,
5146 caseSensitive, outputList);
5147 }
5148
5149 if (!children)
5150 {
5151 rc = entry->remove(&osRC);
5152 updateResultString(outputList, entry, rc, osRC);
5153 }
5154
5155 mc->setRootObject(outputList);
5156 result = mc->marshall();
5157 }
5158 else if (children)
5159 {
5160 if (entry->type() == kSTAFFSDirectory)
5161 {
5162 removeChildren(entry, namePattern, extPattern, entryTypesUInt,
5163 caseSensitive, outputList);
5164 }
5165
5166 mc->setRootObject(outputList);
5167 result = mc->marshall();
5168 }
5169 else
5170 {
5171 rc = entry->remove(&osRC);
5172 updateResultString(outputList, entry, rc, osRC);
5173
5174 mc->setRootObject(outputList);
5175 result = mc->marshall();
5176 }
5177
5178 if (recurse || children)
5179 {
5180 if (outputList->size() != 0)
5181 rc = kSTAFFileDeleteError;
5182
5183 if (ignoreErrors)
5184 result = STAFString();
5185 }
5186 else
5187 {
5188 if (rc == kSTAFBaseOSError)
5189 rc = kSTAFFileDeleteError;
5190 }
5191
5192 return STAFServiceResult(rc, result);
5193 }
5194
5195
handleQuery(const STAFServiceRequest & requestInfo)5196 STAFServiceResult STAFFSService::handleQuery(
5197 const STAFServiceRequest &requestInfo)
5198 {
5199 // Verify that the requesting machine/user has at least trust level 2
5200
5201 IVALIDATE_TRUST(2, "QUERY");
5202
5203 // Parse the request
5204
5205 STAFCommandParseResultPtr parsedResult =
5206 fQueryParser.parse(requestInfo.fRequest);
5207
5208 if (parsedResult->rc != kSTAFOk)
5209 {
5210 return STAFServiceResult(kSTAFInvalidRequestString,
5211 parsedResult->errorBuffer, 0);
5212 }
5213
5214 DEFINE_VAR_POOL_LIST(varPoolList, varPoolListSize, requestInfo);
5215 STAFString entryName;
5216 STAFString result;
5217 STAFString errorBuffer;
5218 STAFRC_t rc = RESOLVE_STRING_OPTION("ENTRY", entryName);
5219
5220 if (rc) return STAFServiceResult(rc, errorBuffer);
5221
5222 STAFFSPath path(entryName);
5223
5224 STAFFSEntryPtr entry;
5225
5226 try
5227 {
5228 if (!path.exists())
5229 return STAFServiceResult(
5230 kSTAFDoesNotExist, "Entry " + entryName + " does not exist");
5231
5232 entry = path.getEntry();
5233 }
5234 catch (STAFBaseOSErrorException &e)
5235 {
5236 STAFString errMsg = "Error on Entry: " + entryName + "\n" +
5237 e.getText() + STAFString(": ") + e.getErrorCode();
5238
5239 return STAFServiceResult(kSTAFBaseOSError, errMsg);
5240 }
5241
5242 // Create a marshalled map of information about the specified entry
5243
5244 STAFObjectPtr mc = STAFObject::createMarshallingContext();
5245 mc->setMapClassDefinition(fQueryInfoClass->reference());
5246
5247 STAFObjectPtr fileInfoMap = fQueryInfoClass->createInstance();
5248
5249 fileInfoMap->put("name", entry->path().asString());
5250 fileInfoMap->put("type", getTypeString(entry->type()));
5251 fileInfoMap->put("size", STAFString(entry->size64()));
5252 fileInfoMap->put("upperSize", STAFString(entry->size().first));
5253 fileInfoMap->put("lowerSize", STAFString(entry->size().second));
5254 fileInfoMap->put("lastModifiedTimestamp", entry->modTime().asString());
5255
5256 if (entry->linkTarget() != "")
5257 fileInfoMap->put("linkTarget", entry->linkTarget());
5258
5259 mc->setRootObject(fileInfoMap);
5260
5261 return STAFServiceResult(kSTAFOk, mc->marshall());
5262 }
5263
5264
handleSet(const STAFServiceRequest & requestInfo)5265 STAFServiceResult STAFFSService::handleSet(
5266 const STAFServiceRequest &requestInfo)
5267 {
5268 // Verify that the requesting machine/user has at least trust level 5
5269
5270 IVALIDATE_TRUST(5, "SET");
5271
5272 // Parse the request
5273
5274 STAFCommandParseResultPtr parsedResult = fSetParser.parse(
5275 requestInfo.fRequest);
5276
5277 if (parsedResult->rc != kSTAFOk)
5278 {
5279 return STAFServiceResult(kSTAFInvalidRequestString,
5280 parsedResult->errorBuffer, 0);
5281 }
5282
5283 DEFINE_VAR_POOL_LIST(varPoolList, varPoolListSize, requestInfo);
5284 STAFString strictTrust;
5285 STAFString errorBuffer;
5286 STAFRC_t rc = RESOLVE_STRING_OPTION("STRICTFSCOPYTRUST", strictTrust);
5287
5288 if (rc) return STAFServiceResult(rc, errorBuffer);
5289
5290 if (strictTrust.isEqualTo(sEnabled, kSTAFStringCaseInsensitive))
5291 {
5292 // Get exclusive access to gStrictFSCopyTrust
5293
5294 STAFMutexSemLock lock(sStrictFSCopyTrustSem);
5295 gStrictFSCopyTrust = 1;
5296 }
5297 else if (strictTrust.isEqualTo(sDisabled, kSTAFStringCaseInsensitive))
5298 {
5299 // Get exclusive access to gStrictFSCopyTrust
5300
5301 STAFMutexSemLock lock(sStrictFSCopyTrustSem);
5302 gStrictFSCopyTrust = 0;
5303 }
5304 else
5305 {
5306 return STAFServiceResult(
5307 kSTAFInvalidValue,
5308 "STRICTFSCOPYTRUST value must be ENABLED or DISABLED. "
5309 "Invalid value: " + strictTrust);
5310 }
5311
5312 return STAFServiceResult(kSTAFOk);
5313 }
5314
5315
handleHelp(const STAFServiceRequest & requestInfo)5316 STAFServiceResult STAFFSService::handleHelp(
5317 const STAFServiceRequest &requestInfo)
5318 {
5319 // Verify that the requesting machine/user has at least trust level 1
5320
5321 IVALIDATE_TRUST(1, "HELP");
5322
5323 return STAFServiceResult(kSTAFOk, sHelpMsg);
5324 }
5325