windows/SysFileSystem.cpp
Go to the documentation of this file.
1 /*----------------------------------------------------------------------------*/
2 /* */
3 /* Copyright (c) 1995, 2004 IBM Corporation. All rights reserved. */
4 /* Copyright (c) 2005-2009 Rexx Language Association. All rights reserved. */
5 /* */
6 /* This program and the accompanying materials are made available under */
7 /* the terms of the Common Public License v1.0 which accompanies this */
8 /* distribution. A copy is also available at the following address: */
9 /* http://www.ibm.com/developerworks/oss/CPLv1.0.htm */
10 /* */
11 /* Redistribution and use in source and binary forms, with or */
12 /* without modification, are permitted provided that the following */
13 /* conditions are met: */
14 /* */
15 /* Redistributions of source code must retain the above copyright */
16 /* notice, this list of conditions and the following disclaimer. */
17 /* Redistributions in binary form must reproduce the above copyright */
18 /* notice, this list of conditions and the following disclaimer in */
19 /* the documentation and/or other materials provided with the distribution. */
20 /* */
21 /* Neither the name of Rexx Language Association nor the names */
22 /* of its contributors may be used to endorse or promote products */
23 /* derived from this software without specific prior written permission. */
24 /* */
25 /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */
26 /* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */
27 /* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS */
28 /* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */
29 /* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */
30 /* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED */
31 /* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, */
32 /* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY */
33 /* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING */
34 /* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS */
35 /* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
36 /* */
37 /*----------------------------------------------------------------------------*/
38 /******************************************************************************/
39 /* REXX Kernel SysFileSystem.cpp */
40 /* */
41 /* Windows implementation of the SysFileSystem class. */
42 /* */
43 /******************************************************************************/
44 
45 #include "RexxCore.h"
46 #include "SysFileSystem.hpp"
47 
51 
52 const char SysFileSystem::EOF_Marker = 0x1a; // the end-of-file marker
53 const char *SysFileSystem::EOL_Marker = "\r\n"; // the end-of-line marker
54 const char SysFileSystem::PathDelimiter = '\\'; // directory path delimiter
55 
56 /*********************************************************************/
57 /* */
58 /* FUNCTION : SearchFileName */
59 /* */
60 /* DESCRIPTION : Search for a given filename, returning the fully */
61 /* resolved name if it is found. */
62 /* */
63 /*********************************************************************/
64 
66  const char * name, /* name of rexx proc to check */
67  char * fullName ) /* fully resolved name */
68 {
69  size_t nameLength; /* length of name */
70 
71  DWORD dwFileAttrib; // file attributes
72  LPTSTR ppszFilePart=NULL; // file name only in buffer
73  UINT errorMode;
74 
75  nameLength = strlen(name); /* get length of incoming name */
76 
77  /* if name is too small or big */
78  if (nameLength < 1 || nameLength > MAX_PATH)
79  {
80  return false; /* then Not a rexx proc name */
81  }
82  /* now try for original name */
83  errorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
84  if (GetFullPathName(name, MAX_PATH, (LPTSTR)fullName, &ppszFilePart))
85  {
86  /* make sure it really exists */
87  // make sure it's not a directory
88  if (-1 != (dwFileAttrib=GetFileAttributes((LPTSTR)fullName)) && (dwFileAttrib != FILE_ATTRIBUTE_DIRECTORY))
89  {
90  /* got it! */
91  SetErrorMode(errorMode);
92  return true;
93  }
94  }
95  /* try searching the path */
96  if ( SearchPath(NULL, (LPCTSTR)name, NULL, MAX_PATH, (LPTSTR)fullName, &ppszFilePart) )
97  {
98  // make sure it's not a directory
99  if (-1 != (dwFileAttrib=GetFileAttributes((LPTSTR)fullName)) && (dwFileAttrib != FILE_ATTRIBUTE_DIRECTORY))
100  {
101  /* got it! */
102  SetErrorMode(errorMode);
103  return true;
104  }
105  }
106 
107  SetErrorMode(errorMode);
108  return false; /* not found */
109 }
110 
111 
112 /**
113  * Generate a temporary file name.
114  *
115  * @return The string name of the temporary file.
116  */
117 const char *SysFileSystem::getTempFileName()
118 {
119  return tmpnam(NULL);
120 }
121 
122 /**
123  * Generate a fully qualified stream name.
124  *
125  * @param unqualifiedName
126  * The starting name.
127  * @param qualifiedName
128  * The fully expanded and canonicalized file name.
129  * @param bufferSize
130  */
131 void SysFileSystem::qualifyStreamName(const char *unqualifiedName, char *qualifiedName, size_t bufferSize)
132 {
133  LPTSTR lpszLastNamePart;
134  UINT errorMode;
135 
136  // If already expanded, there is nothing more to do.
137  if (qualifiedName[0] != '\0')
138  {
139  return;
140  }
141 
142  // If the name is too long, set it to the empty string, otherwise copy the
143  // name to the full area
144  size_t len = strlen(unqualifiedName);
145  if ( len >= bufferSize)
146  {
147  qualifiedName[0] = '\0';
148  return;
149  }
150  else
151  {
152  strcpy(qualifiedName, unqualifiedName);
153  }
154 
155  len = strlen(qualifiedName);
156  /* name end in a colon? */
157  if (qualifiedName[len - 1] == ':')
158  {
159  // this could be the drive letter. If so, make it the root of the current drive.
160  if (len == 2)
161  {
162  strcat(qualifiedName, "\\");
163  }
164  else
165  {
166  // potentially a device, we need to remove the colon.
167  qualifiedName[len - 1] = '\0';
168  return; /* all finished */
169 
170  }
171  }
172  /* get the fully expanded name */
173  errorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
174  DWORD rc = GetFullPathName(qualifiedName, (DWORD)bufferSize, qualifiedName, &lpszLastNamePart);
175  SetErrorMode(errorMode);
176 }
177 
178 
179 /**
180  * Perform a "find first" operation for a file.
181  *
182  * @param name the target name (may include wildcard characters)
183  *
184  * @return true if a file was located, false if not.
185  */
186 bool SysFileSystem::findFirstFile(const char *name)
187 {
188  HANDLE FindHandle;
189  WIN32_FIND_DATA FindData;
190  UINT errorMode;
191 
192  errorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
193  FindHandle = FindFirstFile(name, &FindData);
194  SetErrorMode(errorMode);
195 
196  if (FindHandle != INVALID_HANDLE_VALUE)
197  {
198  FindClose(FindHandle);
199  if ((FindData.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
200  || (FindData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
201  || (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
202  {
203  return false;
204  }
205  else
206  {
207  return true;
208  }
209  }
210  else
211  {
212  return false;
213  }
214 }
215 
216 /**
217  * Check to see if a file with a given name exists.
218  *
219  * @param name The name to check.
220  *
221  * @return True if the file exists, false otherwise.
222  */
223 bool SysFileSystem::fileExists(const char *name)
224 {
225  DWORD dwAttrib = GetFileAttributes(name);
226 
227  return (dwAttrib != INVALID_FILE_ATTRIBUTES &&
228  !((dwAttrib & FILE_ATTRIBUTE_SYSTEM)
229  || (dwAttrib & FILE_ATTRIBUTE_HIDDEN)
230  || (dwAttrib & FILE_ATTRIBUTE_DIRECTORY)));
231 }
232 
233 
234 
235 /**
236  * Extract directory information from a file name.
237  *
238  * @param file The input file name. If this represents a real source file,
239  * this will be fully resolved.
240  *
241  * @return The directory portion of the file name. If the file name
242  * does not include a directory portion, then OREF_NULL is returned.
243  */
245 {
246  const char *pathName = file->getStringData();
247  const char *endPtr = pathName + file->getLength() - 1;
248 
249  // scan backwards looking for a directory delimiter. This name should
250  // be fully qualified, so we don't have to deal with drive letters
251  while (pathName < endPtr)
252  {
253  // find the first directory element?
254  if (*endPtr == '\\')
255  {
256  // extract the directory information, including the final delimiter
257  // and return as a string object.
258  return new_string(pathName, endPtr - pathName + 1);
259  }
260  endPtr--;
261  }
262  return OREF_NULL; // not available
263 }
264 
265 
266 /**
267  * Extract extension information from a file name.
268  *
269  * @param file The input file name. If this represents a real source file,
270  * this will be fully resolved.
271  *
272  * @return The extension portion of the file name. If the file
273  * name does not include an extension portion, then
274  * OREF_NULL is returned.
275  */
277 {
278  const char *pathName = file->getStringData();
279  const char *endPtr = pathName + file->getLength() - 1;
280 
281  // scan backwards looking for a directory delimiter. This name should
282  // be fully qualified, so we don't have to deal with drive letters
283  while (pathName < endPtr)
284  {
285  // find the first directory element?
286  if (*endPtr == '\\')
287  {
288  return OREF_NULL; // found a directory portion before an extension...we're extensionless
289  }
290  // is this the extension dot?
291  else if (*endPtr == '.')
292  {
293  // return everything from the period on. Keeping the period on is a convenience.
294  return new_string(endPtr);
295  }
296  endPtr--;
297  }
298  return OREF_NULL; // not available
299 }
300 
301 
302 /**
303  * Extract file information from a file name.
304  *
305  * @param file The input file name. If this represents a real source file,
306  * this will be fully resolved.
307  *
308  * @return The file portion of the file name. If the file name
309  * does not include a directory portion, then the entire
310  * string is returned
311  */
313 {
314  const char *pathName = file->getStringData();
315  const char *endPtr = pathName + file->getLength() - 1;
316 
317  // scan backwards looking for a directory delimiter. This name should
318  // be fully qualified, so we don't have to deal with drive letters
319  while (pathName < endPtr)
320  {
321  // find the first directory element?
322  if (*endPtr == '\\')
323  {
324  // extract the directory information, including the final delimiter
325  // and return as a string object.
326  return new_string(endPtr);
327  }
328  endPtr--;
329  }
330  return file; // this is all filename
331 }
332 
333 
334 /**
335  * Test if a filename has an extension.
336  *
337  * @param name The name to check.
338  *
339  * @return true if an extension was found on the file, false if there
340  * is no extension.
341  */
342 bool SysFileSystem::hasExtension(const char *name)
343 {
344  const char *endPtr = name + strlen(name) - 1;
345 
346  // scan backwards looking for a directory delimiter. This name should
347  // be fully qualified, so we don't have to deal with drive letters
348  while (name < endPtr)
349  {
350  // find the first directory element?
351  if (*endPtr == '/')
352  {
353  return false; // found a directory portion before an extension...we're extensionless
354  }
355  // is this the extension dot?
356  else if (*endPtr == '.')
357  {
358  // return everything from the period on. Keeping the period on is a convenience.
359  return true;
360  }
361  endPtr--;
362  }
363  return false; // not available
364 }
365 
366 
367 /**
368  * Do a search for a single variation of a filename.
369  *
370  * @param name The name to search for.
371  * @param directory A specific directory to look in first (can be NULL).
372  * @param extension A potential extension to add to the file name (can be NULL).
373  * @param resolvedName
374  * The buffer used to return the resolved file name.
375  *
376  * @return true if the file was located. A true returns indicates the
377  * resolved file name has been placed in the provided buffer.
378  */
379 bool SysFileSystem::searchName(const char *name, const char *path, const char *extension, char *resolvedName)
380 {
381  UnsafeBlock releaser;
382  return primitiveSearchName(name, path, extension, resolvedName);
383 }
384 
385 
386 /**
387  * Do a search for a single variation of a filename.
388  *
389  * NOTE: This version does not do anything with the
390  * kernel lock, so it is callable before the first activity
391  * is set up.
392  *
393  * @param name The name to search for.
394  * @param path
395  * @param extension A potential extension to add to the file name (can be NULL).
396  * @param resolvedName
397  * The buffer used to return the resolved file name.
398  *
399  * @return true if the file was located. A true returns indicates the
400  * resolved file name has been placed in the provided buffer.
401  */
402 bool SysFileSystem::primitiveSearchName(const char *name, const char *path, const char *extension, char *resolvedName)
403 {
404  // this is for building a temporary name
405  char tempName[MAX_PATH + 2];
406 
407  // construct the search name, potentially adding on an extension
408  strncpy(tempName, name, sizeof(tempName));
409  if (extension != NULL)
410  {
411  strncat(tempName, extension, sizeof(tempName) - strlen(tempName) - 1);
412  }
413 
414  *resolvedName = '\0';
415  // if this appears to be a fully qualified name, then check it as-is and
416  // quit. The path searches might give incorrect results if performed with such
417  // a name and this should only check on the raw name.
418  if (hasDirectory(tempName))
419  {
420  // check the file as is first
421  return checkCurrentFile(tempName, resolvedName);
422  }
423 
424  if (searchPath(name, path, extension, resolvedName))
425  {
426  return true;
427  }
428  return false;
429 }
430 
431 
432 /**
433  * Test if a filename has a directory portion
434  *
435  * @param name The name to check.
436  *
437  * @return true if a directory was found on the file, false if
438  * there is no directory.
439  */
440 bool SysFileSystem::hasDirectory(const char *name)
441 {
442  // hasDirectory() means we have enough absolute directory
443  // information at the beginning to bypass performing path searches.
444  // We really only need to look at the first character.
445  return name[0] == '\\' || name[0] == '.' || name[2] == ':';
446 }
447 
448 
449 
450 /**
451  * Try to locate a file using just the raw name passed in, as
452  * opposed to searching along a path for the name.
453  *
454  * @param name The name to use for the search.
455  *
456  * @return An RexxString version of the file name, iff the file was located. Returns
457  * OREF_NULL if the file did not exist.
458  */
459 bool SysFileSystem::checkCurrentFile(const char *name, char *resolvedName)
460 {
461  size_t nameLength = strlen(name); /* get length of incoming name */
462 
463  // make sure we have a valid length for even searching
464  if (nameLength < 1 || nameLength > MAX_PATH)
465  {
466  return false;
467  }
468 
469  // check the name in the current directory
470  unsigned int errorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
471  LPTSTR ppszFilePart=NULL; // file name only in buffer
472 
473  if (GetFullPathName(name, MAX_PATH, (LPTSTR)resolvedName, &ppszFilePart))
474  {
475  DWORD fileAttrib = GetFileAttributes((LPTSTR)resolvedName);
476 
477  // if this is a real file vs. a directory, make sure we return
478  // the long name value in the correct casing
479  if (fileAttrib != INVALID_FILE_ATTRIBUTES && fileAttrib != FILE_ATTRIBUTE_DIRECTORY)
480  {
481  getLongName(resolvedName, MAX_PATH);
482  SetErrorMode(errorMode);
483  return true;
484  }
485  }
486  return false; // not found
487 }
488 
489 
490 /**
491  * Do a path search for a file.
492  *
493  * @param name The name to search for.
494  * @param path The search path to use.
495  * @param extension Any extension that should be added to the search (can be NULL).
496  * @param resolvedName
497  * A buffer used for returning the resolved name.
498  *
499  * @return Returns true if the file was located. If true, the resolvedName
500  * buffer will contain the returned name.
501  */
502 bool SysFileSystem::searchPath(const char *name, const char *path, const char *extension, char *resolvedName)
503 {
504  unsigned int errorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
505 
506  LPTSTR ppszFilePart=NULL; // file name only in buffer
507  if (SearchPath((LPCTSTR)path, (LPCTSTR)name, (LPCTSTR)extension, MAX_PATH, (LPTSTR)resolvedName, &ppszFilePart))
508  {
509  DWORD fileAttrib = GetFileAttributes((LPTSTR)resolvedName);
510 
511  // if this is a real file vs. a directory, make sure we return
512  // the long name value in the correct casing
513  if (fileAttrib != INVALID_FILE_ATTRIBUTES && fileAttrib != FILE_ATTRIBUTE_DIRECTORY)
514  {
515  getLongName(resolvedName, MAX_PATH);
516  SetErrorMode(errorMode);
517  return true;
518  }
519  }
520  return false; // not found
521 }
522 
523 
524 /**
525  * Get the actual name value of a located file, in the exact case
526  * used on the harddrive.
527  *
528  * @param fullName The buffer used for the name.
529  * @param size The size of the buffer.
530  */
531 void SysFileSystem::getLongName(char *fullName, size_t size)
532 {
533  char *p;
534 
535  if (size >= MAX_PATH)
536  {
537  DWORD length = GetLongPathName(fullName, fullName, (DWORD)size);
538 
539  if ( 0 < length && length <= size )
540  {
541  WIN32_FIND_DATA findData;
542  HANDLE hFind = FindFirstFile(fullName, &findData);
543  if ( hFind != INVALID_HANDLE_VALUE )
544  {
545  p = strrchr(fullName, '\\');
546  if ( p )
547  {
548  strcpy(++p, findData . cFileName);
549  }
550  FindClose(hFind);
551  }
552  }
553  }
554  return;
555 }
556 
557 
558 /**
559  * Delete a file from the file system.
560  *
561  * @param name The fully qualified name of the file.
562  *
563  * @return The return code from the delete operation.
564  */
565 bool SysFileSystem::deleteFile(const char *name)
566 {
567  return DeleteFile(name) != 0;
568 }
569 
570 /**
571  * Delete a directory from the file system.
572  *
573  * @param name The name of the target directory.
574  *
575  * @return The return code from the delete operation.
576  */
577 bool SysFileSystem::deleteDirectory(const char *name)
578 {
579  return RemoveDirectory(name) != 0;
580 }
581 
582 
583 /**
584  * Test if a given file name is for a directory.
585  *
586  * @param name The target name.
587  *
588  * @return true if the file is a directory, false for any other
589  * type of entity.
590  */
591 bool SysFileSystem::isDirectory(const char *name)
592 {
593  DWORD dwAttrs = GetFileAttributes(name);
594  return (dwAttrs != 0xffffffff) && (dwAttrs & FILE_ATTRIBUTE_DIRECTORY);
595 }
596 
597 
598 /**
599  * Test is a file is read only.
600  *
601  * @param name The target file name.
602  *
603  * @return true if the file is marked as read-only.
604  */
605 bool SysFileSystem::isReadOnly(const char *name)
606 {
607  DWORD dwAttrs = GetFileAttributes(name);
608  return (dwAttrs != 0xffffffff) && (dwAttrs & FILE_ATTRIBUTE_READONLY);
609 }
610 
611 
612 /**
613  * Test if a file is marked as write-only.
614  *
615  * @param name The target file name.
616  *
617  * @return true if the file is only writeable. false if read
618  * operations are permitted.
619  */
620 bool SysFileSystem::isWriteOnly(const char *name)
621 {
622  // attempt to open for read...if this fails, this is write only
623  HANDLE handle = CreateFile(name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
624  if (handle == INVALID_HANDLE_VALUE)
625  {
626  return true;
627  }
628 
629  CloseHandle(handle);
630  return false;
631 }
632 
633 
634 /**
635  * Test if a give file name is for a real file (not
636  * a directory).
637  *
638  * @param name The target file name.
639  *
640  * @return true if the file is a real file, false if some other
641  * filesystem entity.
642  */
643 bool SysFileSystem::isFile(const char *name)
644 {
645  DWORD dwAttrs = GetFileAttributes(name);
646  return (dwAttrs != 0xffffffff) && (dwAttrs & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT)) == 0;
647 }
648 
649 
650 /**
651  * Test if a file exists using a fully qualified name.
652  *
653  * @param name The target file name.
654  *
655  * @return True if the file exists, false if it is unknown.
656  */
657 bool SysFileSystem::exists(const char *name)
658 {
659  DWORD dwAttrs = GetFileAttributes(name);
660  return (dwAttrs != 0xffffffff);
661 }
662 
663 
664 /**
665  * Get the last modified file date as a file time value.
666  *
667  * @param name The target name.
668  *
669  * @return the file time value for the modified date, or -1 for any
670  * errors.
671  */
673 {
674  HANDLE newHandle = CreateFile(name, FILE_READ_ATTRIBUTES, FILE_SHARE_READ,
675  NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
676  if (newHandle == INVALID_HANDLE_VALUE)
677  {
678  return -1;
679  }
680 
681  FILETIME lastWriteTime;
682  if (!GetFileTime(newHandle, NULL, NULL, &lastWriteTime))
683  {
684  CloseHandle(newHandle);
685  return -1;
686  }
687 
688  /*
689  * Search MSDN for 'Converting a time_t Value to a File Time' for following implementation.
690  */
691  int64_t tempResult = ((int64_t) lastWriteTime.dwHighDateTime << (int64_t)32) | (int64_t) lastWriteTime.dwLowDateTime;
692  int64_t result = (tempResult - 116444736000000000) / 10000000;
693 
694  CloseHandle(newHandle);
695  return result;
696 }
697 
698 
699 /**
700  * Retrieve the size of a file.
701  *
702  * @param name The name of the target file.
703  *
704  * @return the 64-bit file size.
705  */
706 int64_t SysFileSystem::getFileLength(const char *name)
707 {
708  WIN32_FILE_ATTRIBUTE_DATA stat;
709 
710  if (GetFileAttributesEx(name, GetFileExInfoStandard, &stat) == 0)
711  {
712  return 0;
713  }
714 
715  int64_t result = ((int64_t)stat.nFileSizeHigh) << 32;
716  result += (int64_t)stat.nFileSizeLow;
717  return result;
718 }
719 
720 
721 /**
722  * Create a directory in the file system.
723  *
724  * @param name The target name.
725  *
726  * @return The success/failure flag.
727  */
728 bool SysFileSystem::makeDirectory(const char *name)
729 {
730  return CreateDirectory(name, 0) != 0;
731 }
732 
733 
734 /**
735  * Move (rename) a file.
736  *
737  * @param oldName The name of an existing file.
738  * @param newName The new file name.
739  *
740  * @return A success/failure flag.
741  */
742 bool SysFileSystem::moveFile(const char *oldName, const char *newName)
743 {
744  return MoveFile(oldName, newName) != 0;
745 }
746 
747 
748 /**
749  * Test if a given file or directory is hidden.
750  *
751  * @param name The target name.
752  *
753  * @return true if the file or directory is hidden, false otherwise.
754  */
755 bool SysFileSystem::isHidden(const char *name)
756 {
757  DWORD dwAttrs = GetFileAttributes(name);
758  return (dwAttrs != 0xffffffff) && (dwAttrs & FILE_ATTRIBUTE_HIDDEN);
759 }
760 
761 
762 /**
763  * Set the last modified date for a file.
764  *
765  * @param name The target name.
766  * @param time The new file time.
767  *
768  * @return true if the filedate was set correctly, false otherwise.
769  */
770 bool SysFileSystem::setLastModifiedDate(const char *name, int64_t time)
771 {
772  FILETIME fileTime;
773 
774  /**
775  * Open the path ensuring GENERIC_WRITE and FILE_FLAG_BACKUP_SEMANTICS if it's a directory.
776  * The directory modification is only supported on some platforms (NT, Windows2000).
777  */
778  DWORD flags = FILE_ATTRIBUTE_NORMAL;
779  int result = GetFileAttributes(name);
780  if (result == 0xFFFFFFFF)
781  {
782  return false;
783  }
784 
785  if (result & FILE_ATTRIBUTE_DIRECTORY)
786  {
787  flags = FILE_FLAG_BACKUP_SEMANTICS;
788  }
789 
790  HANDLE hFile = CreateFile (name, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
791  NULL, OPEN_EXISTING, flags, NULL);
792  if (hFile == INVALID_HANDLE_VALUE)
793  {
794  return false;
795  }
796 
797  // convert back to a file time
798  int64_t temp = (time * (int64_t)10000000) + 116444736000000000;
799 
800  fileTime.dwHighDateTime = (DWORD)(temp >> 32);
801  fileTime.dwLowDateTime = (DWORD)temp;
802  result = SetFileTime (hFile, (LPFILETIME)NULL, (LPFILETIME)NULL, &fileTime);
803  CloseHandle(hFile);
804  return result != 0;
805 }
806 
807 
808 /**
809  * Set the read-only attribute on a file or directory.
810  *
811  * @param name The target name.
812  *
813  * @return true if the attribute was set, false otherwise.
814  */
815 bool SysFileSystem::setFileReadOnly(const char *name)
816 {
817  DWORD attrs = GetFileAttributes(name);
818  if (attrs == 0xFFFFFFFF)
819  {
820  return false;
821  }
822 
823  attrs = attrs | FILE_ATTRIBUTE_READONLY;
824  return SetFileAttributes(name, attrs) != 0;
825 }
826 
827 
828 /**
829  * indicate whether the file system is case sensitive.
830  *
831  * @return For Windows, always returns false.
832  */
834 {
835  return false;
836 }
837 
838 
839 /**
840  * Retrieve the file system root elements. On Windows,
841  * each of the drives is a root element.
842  *
843  * @return The number of roots located.
844  */
845 int SysFileSystem::getRoots(char *roots)
846 {
847  int length = GetLogicalDriveStrings(MAX_PATH, roots);
848  // elements are returned in the form "d:\", with a null
849  // separator. Each root thus takes up 4 characters
850  return length / 4;
851 }
852 
853 
854 /**
855  * Return the separator used for separating path names.
856  *
857  * @return The ASCII-Z version of the path separator.
858  */
859 const char *SysFileSystem::getSeparator()
860 {
861  return "\\";
862 }
863 
864 
865 /**
866  * Return the separator used for separating search path elements
867  *
868  * @return The ASCII-Z version of the path separator.
869  */
871 {
872  return ";";
873 }
874 
875 
876 /**
877  * Create a new SysFileIterator instance.
878  *
879  * @param p The directory we're iterating over.
880  */
882 {
883  char pattern[MAX_PATH + 1];
884 
885  // save the pattern and convert into a wild card
886  // search
887  strncpy(pattern, p, sizeof(pattern));
888  strncat(pattern, "\\*", sizeof(pattern) - strlen(pattern) - 1);
889 
890  // this assumes we'll fail...if we find something,
891  // we'll flip this
892  completed = true;
893  handle = FindFirstFile (pattern, &findFileData);
894  if (handle != INVALID_HANDLE_VALUE)
895  {
896  // we can still return data
897  completed = false;
898  }
899 }
900 
901 /**
902  * Destructor for the iteration operation.
903  */
905 {
906  close();
907 }
908 
909 
910 /**
911  * close the iterator.
912  */
914 {
915  if (handle != INVALID_HANDLE_VALUE)
916  {
917  FindClose(handle);
918  handle = INVALID_HANDLE_VALUE;
919  }
920 }
921 
922 
923 /**
924  * Check if the iterator has new results it can return.
925  *
926  * @return true if the iterator has another value to return, false if
927  * the iteration is complete.
928  */
930 {
931  return !completed;
932 }
933 
934 
935 /**
936  * Retrieve the next iteration value.
937  *
938  * @param buffer The buffer used to return the value.
939  */
940 void SysFileIterator::next(char *buffer)
941 {
942  if (completed)
943  {
944  strcpy(buffer, "");
945  }
946  else
947  {
948  // copy our current result over
949  strcpy(buffer, findFileData.cFileName);
950  }
951  // now locate the next one
952  if (!FindNextFile (handle, &findFileData))
953  {
954  // we're done once we hit a failure
955  completed = true;
956  close();
957  }
958 }
959 
960 
961 
#define OREF_NULL
Definition: RexxCore.h:61
RexxString * new_string(const char *s, stringsize_t l)
size_t getLength()
const char * getStringData()
WIN32_FIND_DATA findFileData
void next(char *buffer)
SysFileIterator(const char *pattern)
static bool fileExists(const char *name)
static bool checkCurrentFile(const char *name, char *resolvedName)
static bool moveFile(const char *oldName, const char *newName)
static bool setLastModifiedDate(const char *name, int64_t time)
static void getLongName(char *fullName, size_t size)
static const char * getSeparator()
static bool deleteFile(const char *name)
static bool deleteDirectory(const char *name)
static RexxString * extractFile(RexxString *file)
static bool setFileReadOnly(const char *name)
static const char * EOL_Marker
static bool hasDirectory(const char *name)
static const char * getTempFileName()
static int64_t getLastModifiedDate(const char *name)
static const char * getPathSeparator()
static int getRoots(char *roots)
static bool primitiveSearchName(const char *name, const char *path, const char *extension, char *resolvedName)
static bool searchName(const char *name, const char *path, const char *extension, char *resolvedName)
static bool makeDirectory(const char *name)
static RexxString * extractDirectory(RexxString *file)
static RexxString * extractExtension(RexxString *file)
static const char PathDelimiter
static bool isDirectory(const char *name)
static bool searchPath(const char *name, const char *path, char *resolvedName)
static bool isCaseSensitive()
static uint64_t getFileLength(const char *name)
static bool isWriteOnly(const char *name)
static void qualifyStreamName(const char *unqualifiedName, char *qualifiedName, size_t bufferSize)
static bool hasExtension(const char *name)
static const char EOF_Marker
static bool searchFileName(const char *name, char *fullName)
static bool findFirstFile(const char *name)
static bool isHidden(const char *name)
static bool isReadOnly(const char *name)
static bool exists(const char *name)
static bool isFile(const char *name)
int MoveFile(CSTRING fromFile, CSTRING toFile)
int SearchPath(int SearchFlag, const char *path, const char *filename, char *buf, size_t buf_size)
signed __int64 int64_t