~ubuntu-branches/ubuntu/quantal/llvm-3.1/quantal

« back to all changes in this revision

Viewing changes to lib/Support/Windows/Path.inc

  • Committer: Package Import Robot
  • Author(s): Sylvestre Ledru
  • Date: 2012-03-29 19:09:51 UTC
  • Revision ID: package-import@ubuntu.com-20120329190951-aq83ivog4cg8bxun
Tags: upstream-3.1~svn153643
ImportĀ upstreamĀ versionĀ 3.1~svn153643

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//===- llvm/Support/Win32/Path.cpp - Win32 Path Implementation ---*- C++ -*-===//
 
2
//
 
3
//                     The LLVM Compiler Infrastructure
 
4
//
 
5
// This file is distributed under the University of Illinois Open Source
 
6
// License. See LICENSE.TXT for details.
 
7
//
 
8
//===----------------------------------------------------------------------===//
 
9
//
 
10
// This file provides the Win32 specific implementation of the Path class.
 
11
//
 
12
//===----------------------------------------------------------------------===//
 
13
 
 
14
//===----------------------------------------------------------------------===//
 
15
//=== WARNING: Implementation here must contain only generic Win32 code that
 
16
//===          is guaranteed to work on *all* Win32 variants.
 
17
//===----------------------------------------------------------------------===//
 
18
 
 
19
#include "Windows.h"
 
20
#include <malloc.h>
 
21
#include <cstdio>
 
22
 
 
23
// We need to undo a macro defined in Windows.h, otherwise we won't compile:
 
24
#undef CopyFile
 
25
#undef GetCurrentDirectory
 
26
 
 
27
// Windows happily accepts either forward or backward slashes, though any path
 
28
// returned by a Win32 API will have backward slashes.  As LLVM code basically
 
29
// assumes forward slashes are used, backward slashs are converted where they
 
30
// can be introduced into a path.
 
31
//
 
32
// Another invariant is that a path ends with a slash if and only if the path
 
33
// is a root directory.  Any other use of a trailing slash is stripped.  Unlike
 
34
// in Unix, Windows has a rather complicated notion of a root path and this
 
35
// invariant helps simply the code.
 
36
 
 
37
static void FlipBackSlashes(std::string& s) {
 
38
  for (size_t i = 0; i < s.size(); i++)
 
39
    if (s[i] == '\\')
 
40
      s[i] = '/';
 
41
}
 
42
 
 
43
namespace llvm {
 
44
namespace sys {
 
45
 
 
46
const char PathSeparator = ';';
 
47
 
 
48
StringRef Path::GetEXESuffix() {
 
49
  return "exe";
 
50
}
 
51
 
 
52
Path::Path(llvm::StringRef p)
 
53
  : path(p) {
 
54
  FlipBackSlashes(path);
 
55
}
 
56
 
 
57
Path::Path(const char *StrStart, unsigned StrLen)
 
58
  : path(StrStart, StrLen) {
 
59
  FlipBackSlashes(path);
 
60
}
 
61
 
 
62
Path&
 
63
Path::operator=(StringRef that) {
 
64
  path.assign(that.data(), that.size());
 
65
  FlipBackSlashes(path);
 
66
  return *this;
 
67
}
 
68
 
 
69
bool
 
70
Path::isValid() const {
 
71
  if (path.empty())
 
72
    return false;
 
73
 
 
74
  size_t len = path.size();
 
75
  // If there is a null character, it and all its successors are ignored.
 
76
  size_t pos = path.find_first_of('\0');
 
77
  if (pos != std::string::npos)
 
78
    len = pos;
 
79
 
 
80
  // If there is a colon, it must be the second character, preceded by a letter
 
81
  // and followed by something.
 
82
  pos = path.rfind(':',len);
 
83
  size_t rootslash = 0;
 
84
  if (pos != std::string::npos) {
 
85
    if (pos != 1 || !isalpha(path[0]) || len < 3)
 
86
      return false;
 
87
      rootslash = 2;
 
88
  }
 
89
 
 
90
  // Look for a UNC path, and if found adjust our notion of the root slash.
 
91
  if (len > 3 && path[0] == '/' && path[1] == '/') {
 
92
    rootslash = path.find('/', 2);
 
93
    if (rootslash == std::string::npos)
 
94
      rootslash = 0;
 
95
  }
 
96
 
 
97
  // Check for illegal characters.
 
98
  if (path.find_first_of("\\<>\"|\001\002\003\004\005\006\007\010\011\012"
 
99
                         "\013\014\015\016\017\020\021\022\023\024\025\026"
 
100
                         "\027\030\031\032\033\034\035\036\037")
 
101
      != std::string::npos)
 
102
    return false;
 
103
 
 
104
  // Remove trailing slash, unless it's a root slash.
 
105
  if (len > rootslash+1 && path[len-1] == '/')
 
106
    path.erase(--len);
 
107
 
 
108
  // Check each component for legality.
 
109
  for (pos = 0; pos < len; ++pos) {
 
110
    // A component may not end in a space.
 
111
    if (path[pos] == ' ') {
 
112
      if (pos+1 == len || path[pos+1] == '/' || path[pos+1] == '\0')
 
113
        return false;
 
114
    }
 
115
 
 
116
    // A component may not end in a period.
 
117
    if (path[pos] == '.') {
 
118
      if (pos+1 == len || path[pos+1] == '/') {
 
119
        // Unless it is the pseudo-directory "."...
 
120
        if (pos == 0 || path[pos-1] == '/' || path[pos-1] == ':')
 
121
          return true;
 
122
        // or "..".
 
123
        if (pos > 0 && path[pos-1] == '.') {
 
124
          if (pos == 1 || path[pos-2] == '/' || path[pos-2] == ':')
 
125
            return true;
 
126
        }
 
127
        return false;
 
128
      }
 
129
    }
 
130
  }
 
131
 
 
132
  return true;
 
133
}
 
134
 
 
135
void Path::makeAbsolute() {
 
136
  TCHAR  FullPath[MAX_PATH + 1] = {0};
 
137
  LPTSTR FilePart = NULL;
 
138
 
 
139
  DWORD RetLength = ::GetFullPathNameA(path.c_str(),
 
140
                        sizeof(FullPath)/sizeof(FullPath[0]),
 
141
                        FullPath, &FilePart);
 
142
 
 
143
  if (0 == RetLength) {
 
144
    // FIXME: Report the error GetLastError()
 
145
    assert(0 && "Unable to make absolute path!");
 
146
  } else if (RetLength > MAX_PATH) {
 
147
    // FIXME: Report too small buffer (needed RetLength bytes).
 
148
    assert(0 && "Unable to make absolute path!");
 
149
  } else {
 
150
    path = FullPath;
 
151
  }
 
152
}
 
153
 
 
154
bool
 
155
Path::isAbsolute(const char *NameStart, unsigned NameLen) {
 
156
  assert(NameStart);
 
157
  // FIXME: This does not handle correctly an absolute path starting from
 
158
  // a drive letter or in UNC format.
 
159
  switch (NameLen) {
 
160
  case 0:
 
161
    return false;
 
162
  case 1:
 
163
  case 2:
 
164
    return NameStart[0] == '/';
 
165
  default:
 
166
    return
 
167
      (NameStart[0] == '/' || (NameStart[1] == ':' && NameStart[2] == '/')) ||
 
168
      (NameStart[0] == '\\' || (NameStart[1] == ':' && NameStart[2] == '\\'));
 
169
  }
 
170
}
 
171
 
 
172
bool
 
173
Path::isAbsolute() const {
 
174
  // FIXME: This does not handle correctly an absolute path starting from
 
175
  // a drive letter or in UNC format.
 
176
  switch (path.length()) {
 
177
    case 0:
 
178
      return false;
 
179
    case 1:
 
180
    case 2:
 
181
      return path[0] == '/';
 
182
    default:
 
183
      return path[0] == '/' || (path[1] == ':' && path[2] == '/');
 
184
  }
 
185
}
 
186
 
 
187
static Path *TempDirectory;
 
188
 
 
189
Path
 
190
Path::GetTemporaryDirectory(std::string* ErrMsg) {
 
191
  if (TempDirectory)
 
192
    return *TempDirectory;
 
193
 
 
194
  char pathname[MAX_PATH];
 
195
  if (!GetTempPath(MAX_PATH, pathname)) {
 
196
    if (ErrMsg)
 
197
      *ErrMsg = "Can't determine temporary directory";
 
198
    return Path();
 
199
  }
 
200
 
 
201
  Path result;
 
202
  result.set(pathname);
 
203
 
 
204
  // Append a subdirectory passed on our process id so multiple LLVMs don't
 
205
  // step on each other's toes.
 
206
#ifdef __MINGW32__
 
207
  // Mingw's Win32 header files are broken.
 
208
  sprintf(pathname, "LLVM_%u", unsigned(GetCurrentProcessId()));
 
209
#else
 
210
  sprintf(pathname, "LLVM_%u", GetCurrentProcessId());
 
211
#endif
 
212
  result.appendComponent(pathname);
 
213
 
 
214
  // If there's a directory left over from a previous LLVM execution that
 
215
  // happened to have the same process id, get rid of it.
 
216
  result.eraseFromDisk(true);
 
217
 
 
218
  // And finally (re-)create the empty directory.
 
219
  result.createDirectoryOnDisk(false);
 
220
  TempDirectory = new Path(result);
 
221
  return *TempDirectory;
 
222
}
 
223
 
 
224
// FIXME: the following set of functions don't map to Windows very well.
 
225
Path
 
226
Path::GetRootDirectory() {
 
227
  // This is the only notion that that Windows has of a root directory. Nothing
 
228
  // is here except for drives.
 
229
  return Path("file:///");
 
230
}
 
231
 
 
232
void
 
233
Path::GetSystemLibraryPaths(std::vector<sys::Path>& Paths) {
 
234
  char buff[MAX_PATH];
 
235
  // Generic form of C:\Windows\System32
 
236
  HRESULT res =  SHGetFolderPathA(NULL,
 
237
                                  CSIDL_FLAG_CREATE | CSIDL_SYSTEM,
 
238
                                  NULL,
 
239
                                  SHGFP_TYPE_CURRENT,
 
240
                                  buff);
 
241
  if (res != S_OK) {
 
242
    assert(0 && "Failed to get system directory");
 
243
    return;
 
244
  }
 
245
  Paths.push_back(sys::Path(buff));
 
246
 
 
247
  // Reset buff.
 
248
  buff[0] = 0;
 
249
  // Generic form of C:\Windows
 
250
  res =  SHGetFolderPathA(NULL,
 
251
                          CSIDL_FLAG_CREATE | CSIDL_WINDOWS,
 
252
                          NULL,
 
253
                          SHGFP_TYPE_CURRENT,
 
254
                          buff);
 
255
  if (res != S_OK) {
 
256
    assert(0 && "Failed to get windows directory");
 
257
    return;
 
258
  }
 
259
  Paths.push_back(sys::Path(buff));
 
260
}
 
261
 
 
262
void
 
263
Path::GetBitcodeLibraryPaths(std::vector<sys::Path>& Paths) {
 
264
  char * env_var = getenv("LLVM_LIB_SEARCH_PATH");
 
265
  if (env_var != 0) {
 
266
    getPathList(env_var,Paths);
 
267
  }
 
268
#ifdef LLVM_LIBDIR
 
269
  {
 
270
    Path tmpPath;
 
271
    if (tmpPath.set(LLVM_LIBDIR))
 
272
      if (tmpPath.canRead())
 
273
        Paths.push_back(tmpPath);
 
274
  }
 
275
#endif
 
276
  GetSystemLibraryPaths(Paths);
 
277
}
 
278
 
 
279
Path
 
280
Path::GetUserHomeDirectory() {
 
281
  char buff[MAX_PATH];
 
282
  HRESULT res = SHGetFolderPathA(NULL,
 
283
                                 CSIDL_FLAG_CREATE | CSIDL_APPDATA,
 
284
                                 NULL,
 
285
                                 SHGFP_TYPE_CURRENT,
 
286
                                 buff);
 
287
  if (res != S_OK)
 
288
    assert(0 && "Failed to get user home directory");
 
289
  return Path(buff);
 
290
}
 
291
 
 
292
Path
 
293
Path::GetCurrentDirectory() {
 
294
  char pathname[MAX_PATH];
 
295
  ::GetCurrentDirectoryA(MAX_PATH,pathname);
 
296
  return Path(pathname);
 
297
}
 
298
 
 
299
/// GetMainExecutable - Return the path to the main executable, given the
 
300
/// value of argv[0] from program startup.
 
301
Path Path::GetMainExecutable(const char *argv0, void *MainAddr) {
 
302
  char pathname[MAX_PATH];
 
303
  DWORD ret = ::GetModuleFileNameA(NULL, pathname, MAX_PATH);
 
304
  return ret != MAX_PATH ? Path(pathname) : Path();
 
305
}
 
306
 
 
307
 
 
308
// FIXME: the above set of functions don't map to Windows very well.
 
309
 
 
310
 
 
311
StringRef Path::getDirname() const {
 
312
  return getDirnameCharSep(path, "/");
 
313
}
 
314
 
 
315
StringRef
 
316
Path::getBasename() const {
 
317
  // Find the last slash
 
318
  size_t slash = path.rfind('/');
 
319
  if (slash == std::string::npos)
 
320
    slash = 0;
 
321
  else
 
322
    slash++;
 
323
 
 
324
  size_t dot = path.rfind('.');
 
325
  if (dot == std::string::npos || dot < slash)
 
326
    return StringRef(path).substr(slash);
 
327
  else
 
328
    return StringRef(path).substr(slash, dot - slash);
 
329
}
 
330
 
 
331
StringRef
 
332
Path::getSuffix() const {
 
333
  // Find the last slash
 
334
  size_t slash = path.rfind('/');
 
335
  if (slash == std::string::npos)
 
336
    slash = 0;
 
337
  else
 
338
    slash++;
 
339
 
 
340
  size_t dot = path.rfind('.');
 
341
  if (dot == std::string::npos || dot < slash)
 
342
    return StringRef("");
 
343
  else
 
344
    return StringRef(path).substr(dot + 1);
 
345
}
 
346
 
 
347
bool
 
348
Path::exists() const {
 
349
  DWORD attr = GetFileAttributes(path.c_str());
 
350
  return attr != INVALID_FILE_ATTRIBUTES;
 
351
}
 
352
 
 
353
bool
 
354
Path::isDirectory() const {
 
355
  DWORD attr = GetFileAttributes(path.c_str());
 
356
  return (attr != INVALID_FILE_ATTRIBUTES) &&
 
357
         (attr & FILE_ATTRIBUTE_DIRECTORY);
 
358
}
 
359
 
 
360
bool
 
361
Path::isSymLink() const {
 
362
  DWORD attributes = GetFileAttributes(path.c_str());
 
363
 
 
364
  if (attributes == INVALID_FILE_ATTRIBUTES)
 
365
    // There's no sane way to report this :(.
 
366
    assert(0 && "GetFileAttributes returned INVALID_FILE_ATTRIBUTES");
 
367
 
 
368
  // This isn't exactly what defines a NTFS symlink, but it is only true for
 
369
  // paths that act like a symlink.
 
370
  return attributes & FILE_ATTRIBUTE_REPARSE_POINT;
 
371
}
 
372
 
 
373
bool
 
374
Path::canRead() const {
 
375
  // FIXME: take security attributes into account.
 
376
  DWORD attr = GetFileAttributes(path.c_str());
 
377
  return attr != INVALID_FILE_ATTRIBUTES;
 
378
}
 
379
 
 
380
bool
 
381
Path::canWrite() const {
 
382
  // FIXME: take security attributes into account.
 
383
  DWORD attr = GetFileAttributes(path.c_str());
 
384
  return (attr != INVALID_FILE_ATTRIBUTES) && !(attr & FILE_ATTRIBUTE_READONLY);
 
385
}
 
386
 
 
387
bool
 
388
Path::canExecute() const {
 
389
  // FIXME: take security attributes into account.
 
390
  DWORD attr = GetFileAttributes(path.c_str());
 
391
  return attr != INVALID_FILE_ATTRIBUTES;
 
392
}
 
393
 
 
394
bool
 
395
Path::isRegularFile() const {
 
396
  bool res;
 
397
  if (fs::is_regular_file(path, res))
 
398
    return false;
 
399
  return res;
 
400
}
 
401
 
 
402
StringRef
 
403
Path::getLast() const {
 
404
  // Find the last slash
 
405
  size_t pos = path.rfind('/');
 
406
 
 
407
  // Handle the corner cases
 
408
  if (pos == std::string::npos)
 
409
    return path;
 
410
 
 
411
  // If the last character is a slash, we have a root directory
 
412
  if (pos == path.length()-1)
 
413
    return path;
 
414
 
 
415
  // Return everything after the last slash
 
416
  return StringRef(path).substr(pos+1);
 
417
}
 
418
 
 
419
const FileStatus *
 
420
PathWithStatus::getFileStatus(bool update, std::string *ErrStr) const {
 
421
  if (!fsIsValid || update) {
 
422
    WIN32_FILE_ATTRIBUTE_DATA fi;
 
423
    if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi)) {
 
424
      MakeErrMsg(ErrStr, "getStatusInfo():" + std::string(path) +
 
425
                      ": Can't get status: ");
 
426
      return 0;
 
427
    }
 
428
 
 
429
    status.fileSize = fi.nFileSizeHigh;
 
430
    status.fileSize <<= sizeof(fi.nFileSizeHigh)*8;
 
431
    status.fileSize += fi.nFileSizeLow;
 
432
 
 
433
    status.mode = fi.dwFileAttributes & FILE_ATTRIBUTE_READONLY ? 0555 : 0777;
 
434
    status.user = 9999;    // Not applicable to Windows, so...
 
435
    status.group = 9999;   // Not applicable to Windows, so...
 
436
 
 
437
    // FIXME: this is only unique if the file is accessed by the same file path.
 
438
    // How do we do this for C:\dir\file and ..\dir\file ? Unix has inode
 
439
    // numbers, but the concept doesn't exist in Windows.
 
440
    status.uniqueID = 0;
 
441
    for (unsigned i = 0; i < path.length(); ++i)
 
442
      status.uniqueID += path[i];
 
443
 
 
444
    ULARGE_INTEGER ui;
 
445
    ui.LowPart = fi.ftLastWriteTime.dwLowDateTime;
 
446
    ui.HighPart = fi.ftLastWriteTime.dwHighDateTime;
 
447
    status.modTime.fromWin32Time(ui.QuadPart);
 
448
 
 
449
    status.isDir = fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
 
450
    fsIsValid = true;
 
451
  }
 
452
  return &status;
 
453
}
 
454
 
 
455
bool Path::makeReadableOnDisk(std::string* ErrMsg) {
 
456
  // All files are readable on Windows (ignoring security attributes).
 
457
  return false;
 
458
}
 
459
 
 
460
bool Path::makeWriteableOnDisk(std::string* ErrMsg) {
 
461
  DWORD attr = GetFileAttributes(path.c_str());
 
462
 
 
463
  // If it doesn't exist, we're done.
 
464
  if (attr == INVALID_FILE_ATTRIBUTES)
 
465
    return false;
 
466
 
 
467
  if (attr & FILE_ATTRIBUTE_READONLY) {
 
468
    if (!SetFileAttributes(path.c_str(), attr & ~FILE_ATTRIBUTE_READONLY)) {
 
469
      MakeErrMsg(ErrMsg, std::string(path) + ": Can't make file writable: ");
 
470
      return true;
 
471
    }
 
472
  }
 
473
  return false;
 
474
}
 
475
 
 
476
bool Path::makeExecutableOnDisk(std::string* ErrMsg) {
 
477
  // All files are executable on Windows (ignoring security attributes).
 
478
  return false;
 
479
}
 
480
 
 
481
bool
 
482
Path::getDirectoryContents(std::set<Path>& result, std::string* ErrMsg) const {
 
483
  WIN32_FILE_ATTRIBUTE_DATA fi;
 
484
  if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi)) {
 
485
    MakeErrMsg(ErrMsg, path + ": can't get status of file");
 
486
    return true;
 
487
  }
 
488
 
 
489
  if (!(fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
 
490
    if (ErrMsg)
 
491
      *ErrMsg = path + ": not a directory";
 
492
    return true;
 
493
  }
 
494
 
 
495
  result.clear();
 
496
  WIN32_FIND_DATA fd;
 
497
  std::string searchpath = path;
 
498
  if (path.size() == 0 || searchpath[path.size()-1] == '/')
 
499
    searchpath += "*";
 
500
  else
 
501
    searchpath += "/*";
 
502
 
 
503
  HANDLE h = FindFirstFile(searchpath.c_str(), &fd);
 
504
  if (h == INVALID_HANDLE_VALUE) {
 
505
    if (GetLastError() == ERROR_FILE_NOT_FOUND)
 
506
      return true; // not really an error, now is it?
 
507
    MakeErrMsg(ErrMsg, path + ": Can't read directory: ");
 
508
    return true;
 
509
  }
 
510
 
 
511
  do {
 
512
    if (fd.cFileName[0] == '.')
 
513
      continue;
 
514
    Path aPath(path);
 
515
    aPath.appendComponent(&fd.cFileName[0]);
 
516
    result.insert(aPath);
 
517
  } while (FindNextFile(h, &fd));
 
518
 
 
519
  DWORD err = GetLastError();
 
520
  FindClose(h);
 
521
  if (err != ERROR_NO_MORE_FILES) {
 
522
    SetLastError(err);
 
523
    MakeErrMsg(ErrMsg, path + ": Can't read directory: ");
 
524
    return true;
 
525
  }
 
526
  return false;
 
527
}
 
528
 
 
529
bool
 
530
Path::set(StringRef a_path) {
 
531
  if (a_path.empty())
 
532
    return false;
 
533
  std::string save(path);
 
534
  path = a_path;
 
535
  FlipBackSlashes(path);
 
536
  if (!isValid()) {
 
537
    path = save;
 
538
    return false;
 
539
  }
 
540
  return true;
 
541
}
 
542
 
 
543
bool
 
544
Path::appendComponent(StringRef name) {
 
545
  if (name.empty())
 
546
    return false;
 
547
  std::string save(path);
 
548
  if (!path.empty()) {
 
549
    size_t last = path.size() - 1;
 
550
    if (path[last] != '/')
 
551
      path += '/';
 
552
  }
 
553
  path += name;
 
554
  if (!isValid()) {
 
555
    path = save;
 
556
    return false;
 
557
  }
 
558
  return true;
 
559
}
 
560
 
 
561
bool
 
562
Path::eraseComponent() {
 
563
  size_t slashpos = path.rfind('/',path.size());
 
564
  if (slashpos == path.size() - 1 || slashpos == std::string::npos)
 
565
    return false;
 
566
  std::string save(path);
 
567
  path.erase(slashpos);
 
568
  if (!isValid()) {
 
569
    path = save;
 
570
    return false;
 
571
  }
 
572
  return true;
 
573
}
 
574
 
 
575
bool
 
576
Path::eraseSuffix() {
 
577
  size_t dotpos = path.rfind('.',path.size());
 
578
  size_t slashpos = path.rfind('/',path.size());
 
579
  if (dotpos != std::string::npos) {
 
580
    if (slashpos == std::string::npos || dotpos > slashpos+1) {
 
581
      std::string save(path);
 
582
      path.erase(dotpos, path.size()-dotpos);
 
583
      if (!isValid()) {
 
584
        path = save;
 
585
        return false;
 
586
      }
 
587
      return true;
 
588
    }
 
589
  }
 
590
  return false;
 
591
}
 
592
 
 
593
inline bool PathMsg(std::string* ErrMsg, const char* pathname, const char*msg) {
 
594
  if (ErrMsg)
 
595
    *ErrMsg = std::string(pathname) + ": " + std::string(msg);
 
596
  return true;
 
597
}
 
598
 
 
599
bool
 
600
Path::createDirectoryOnDisk(bool create_parents, std::string* ErrMsg) {
 
601
  // Get a writeable copy of the path name
 
602
  size_t len = path.length();
 
603
  char *pathname = reinterpret_cast<char *>(_alloca(len+2));
 
604
  path.copy(pathname, len);
 
605
  pathname[len] = 0;
 
606
 
 
607
  // Make sure it ends with a slash.
 
608
  if (len == 0 || pathname[len - 1] != '/') {
 
609
    pathname[len] = '/';
 
610
    pathname[++len] = 0;
 
611
  }
 
612
 
 
613
  // Determine starting point for initial / search.
 
614
  char *next = pathname;
 
615
  if (pathname[0] == '/' && pathname[1] == '/') {
 
616
    // Skip host name.
 
617
    next = strchr(pathname+2, '/');
 
618
    if (next == NULL)
 
619
      return PathMsg(ErrMsg, pathname, "badly formed remote directory");
 
620
 
 
621
    // Skip share name.
 
622
    next = strchr(next+1, '/');
 
623
    if (next == NULL)
 
624
      return PathMsg(ErrMsg, pathname,"badly formed remote directory");
 
625
 
 
626
    next++;
 
627
    if (*next == 0)
 
628
      return PathMsg(ErrMsg, pathname, "badly formed remote directory");
 
629
 
 
630
  } else {
 
631
    if (pathname[1] == ':')
 
632
      next += 2;    // skip drive letter
 
633
    if (*next == '/')
 
634
      next++;       // skip root directory
 
635
  }
 
636
 
 
637
  // If we're supposed to create intermediate directories
 
638
  if (create_parents) {
 
639
    // Loop through the directory components until we're done
 
640
    while (*next) {
 
641
      next = strchr(next, '/');
 
642
      *next = 0;
 
643
      if (!CreateDirectory(pathname, NULL) &&
 
644
          GetLastError() != ERROR_ALREADY_EXISTS)
 
645
          return MakeErrMsg(ErrMsg,
 
646
            std::string(pathname) + ": Can't create directory: ");
 
647
      *next++ = '/';
 
648
    }
 
649
  } else {
 
650
    // Drop trailing slash.
 
651
    pathname[len-1] = 0;
 
652
    if (!CreateDirectory(pathname, NULL) &&
 
653
        GetLastError() != ERROR_ALREADY_EXISTS) {
 
654
      return MakeErrMsg(ErrMsg, std::string(pathname) +
 
655
                        ": Can't create directory: ");
 
656
    }
 
657
  }
 
658
  return false;
 
659
}
 
660
 
 
661
bool
 
662
Path::createFileOnDisk(std::string* ErrMsg) {
 
663
  // Create the file
 
664
  HANDLE h = CreateFile(path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW,
 
665
                        FILE_ATTRIBUTE_NORMAL, NULL);
 
666
  if (h == INVALID_HANDLE_VALUE)
 
667
    return MakeErrMsg(ErrMsg, path + ": Can't create file: ");
 
668
 
 
669
  CloseHandle(h);
 
670
  return false;
 
671
}
 
672
 
 
673
bool
 
674
Path::eraseFromDisk(bool remove_contents, std::string *ErrStr) const {
 
675
  WIN32_FILE_ATTRIBUTE_DATA fi;
 
676
  if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi))
 
677
    return true;
 
678
 
 
679
  if (fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
 
680
    // If it doesn't exist, we're done.
 
681
    bool Exists;
 
682
    if (fs::exists(path, Exists) || !Exists)
 
683
      return false;
 
684
 
 
685
    char *pathname = reinterpret_cast<char *>(_alloca(path.length()+3));
 
686
    int lastchar = path.length() - 1 ;
 
687
    path.copy(pathname, lastchar+1);
 
688
 
 
689
    // Make path end with '/*'.
 
690
    if (pathname[lastchar] != '/')
 
691
      pathname[++lastchar] = '/';
 
692
    pathname[lastchar+1] = '*';
 
693
    pathname[lastchar+2] = 0;
 
694
 
 
695
    if (remove_contents) {
 
696
      WIN32_FIND_DATA fd;
 
697
      HANDLE h = FindFirstFile(pathname, &fd);
 
698
 
 
699
      // It's a bad idea to alter the contents of a directory while enumerating
 
700
      // its contents. So build a list of its contents first, then destroy them.
 
701
 
 
702
      if (h != INVALID_HANDLE_VALUE) {
 
703
        std::vector<Path> list;
 
704
 
 
705
        do {
 
706
          if (strcmp(fd.cFileName, ".") == 0)
 
707
            continue;
 
708
          if (strcmp(fd.cFileName, "..") == 0)
 
709
            continue;
 
710
 
 
711
          Path aPath(path);
 
712
          aPath.appendComponent(&fd.cFileName[0]);
 
713
          list.push_back(aPath);
 
714
        } while (FindNextFile(h, &fd));
 
715
 
 
716
        DWORD err = GetLastError();
 
717
        FindClose(h);
 
718
        if (err != ERROR_NO_MORE_FILES) {
 
719
          SetLastError(err);
 
720
          return MakeErrMsg(ErrStr, path + ": Can't read directory: ");
 
721
        }
 
722
 
 
723
        for (std::vector<Path>::iterator I = list.begin(); I != list.end();
 
724
             ++I) {
 
725
          Path &aPath = *I;
 
726
          aPath.eraseFromDisk(true);
 
727
        }
 
728
      } else {
 
729
        if (GetLastError() != ERROR_FILE_NOT_FOUND)
 
730
          return MakeErrMsg(ErrStr, path + ": Can't read directory: ");
 
731
      }
 
732
    }
 
733
 
 
734
    pathname[lastchar] = 0;
 
735
    if (!RemoveDirectory(pathname))
 
736
      return MakeErrMsg(ErrStr,
 
737
        std::string(pathname) + ": Can't destroy directory: ");
 
738
    return false;
 
739
  } else {
 
740
    // Read-only files cannot be deleted on Windows.  Must remove the read-only
 
741
    // attribute first.
 
742
    if (fi.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
 
743
      if (!SetFileAttributes(path.c_str(),
 
744
                             fi.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY))
 
745
        return MakeErrMsg(ErrStr, path + ": Can't destroy file: ");
 
746
    }
 
747
 
 
748
    if (!DeleteFile(path.c_str()))
 
749
      return MakeErrMsg(ErrStr, path + ": Can't destroy file: ");
 
750
    return false;
 
751
  }
 
752
}
 
753
 
 
754
bool Path::getMagicNumber(std::string& Magic, unsigned len) const {
 
755
  assert(len < 1024 && "Request for magic string too long");
 
756
  char* buf = reinterpret_cast<char*>(alloca(len));
 
757
 
 
758
  HANDLE h = CreateFile(path.c_str(),
 
759
                        GENERIC_READ,
 
760
                        FILE_SHARE_READ,
 
761
                        NULL,
 
762
                        OPEN_EXISTING,
 
763
                        FILE_ATTRIBUTE_NORMAL,
 
764
                        NULL);
 
765
  if (h == INVALID_HANDLE_VALUE)
 
766
    return false;
 
767
 
 
768
  DWORD nRead = 0;
 
769
  BOOL ret = ReadFile(h, buf, len, &nRead, NULL);
 
770
  CloseHandle(h);
 
771
 
 
772
  if (!ret || nRead != len)
 
773
    return false;
 
774
 
 
775
  Magic = std::string(buf, len);
 
776
  return true;
 
777
}
 
778
 
 
779
bool
 
780
Path::renamePathOnDisk(const Path& newName, std::string* ErrMsg) {
 
781
  if (!MoveFileEx(path.c_str(), newName.c_str(), MOVEFILE_REPLACE_EXISTING))
 
782
    return MakeErrMsg(ErrMsg, "Can't move '" + path + "' to '" + newName.path
 
783
        + "': ");
 
784
  return false;
 
785
}
 
786
 
 
787
bool
 
788
Path::setStatusInfoOnDisk(const FileStatus &si, std::string *ErrMsg) const {
 
789
  // FIXME: should work on directories also.
 
790
  if (!si.isFile) {
 
791
    return true;
 
792
  }
 
793
 
 
794
  HANDLE h = CreateFile(path.c_str(),
 
795
                        FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES,
 
796
                        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
 
797
                        NULL,
 
798
                        OPEN_EXISTING,
 
799
                        FILE_ATTRIBUTE_NORMAL,
 
800
                        NULL);
 
801
  if (h == INVALID_HANDLE_VALUE)
 
802
    return true;
 
803
 
 
804
  BY_HANDLE_FILE_INFORMATION bhfi;
 
805
  if (!GetFileInformationByHandle(h, &bhfi)) {
 
806
    DWORD err = GetLastError();
 
807
    CloseHandle(h);
 
808
    SetLastError(err);
 
809
    return MakeErrMsg(ErrMsg, path + ": GetFileInformationByHandle: ");
 
810
  }
 
811
 
 
812
  ULARGE_INTEGER ui;
 
813
  ui.QuadPart = si.modTime.toWin32Time();
 
814
  FILETIME ft;
 
815
  ft.dwLowDateTime = ui.LowPart;
 
816
  ft.dwHighDateTime = ui.HighPart;
 
817
  BOOL ret = SetFileTime(h, NULL, &ft, &ft);
 
818
  DWORD err = GetLastError();
 
819
  CloseHandle(h);
 
820
  if (!ret) {
 
821
    SetLastError(err);
 
822
    return MakeErrMsg(ErrMsg, path + ": SetFileTime: ");
 
823
  }
 
824
 
 
825
  // Best we can do with Unix permission bits is to interpret the owner
 
826
  // writable bit.
 
827
  if (si.mode & 0200) {
 
828
    if (bhfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
 
829
      if (!SetFileAttributes(path.c_str(),
 
830
              bhfi.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY))
 
831
        return MakeErrMsg(ErrMsg, path + ": SetFileAttributes: ");
 
832
    }
 
833
  } else {
 
834
    if (!(bhfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) {
 
835
      if (!SetFileAttributes(path.c_str(),
 
836
              bhfi.dwFileAttributes | FILE_ATTRIBUTE_READONLY))
 
837
        return MakeErrMsg(ErrMsg, path + ": SetFileAttributes: ");
 
838
    }
 
839
  }
 
840
 
 
841
  return false;
 
842
}
 
843
 
 
844
bool
 
845
CopyFile(const sys::Path &Dest, const sys::Path &Src, std::string* ErrMsg) {
 
846
  // Can't use CopyFile macro defined in Windows.h because it would mess up the
 
847
  // above line.  We use the expansion it would have in a non-UNICODE build.
 
848
  if (!::CopyFileA(Src.c_str(), Dest.c_str(), false))
 
849
    return MakeErrMsg(ErrMsg, "Can't copy '" + Src.str() +
 
850
               "' to '" + Dest.str() + "': ");
 
851
  return false;
 
852
}
 
853
 
 
854
bool
 
855
Path::makeUnique(bool reuse_current, std::string* ErrMsg) {
 
856
  bool Exists;
 
857
  if (reuse_current && (fs::exists(path, Exists) || !Exists))
 
858
    return false; // File doesn't exist already, just use it!
 
859
 
 
860
  // Reserve space for -XXXXXX at the end.
 
861
  char *FNBuffer = (char*) alloca(path.size()+8);
 
862
  unsigned offset = path.size();
 
863
  path.copy(FNBuffer, offset);
 
864
 
 
865
  // Find a numeric suffix that isn't used by an existing file.  Assume there
 
866
  // won't be more than 1 million files with the same prefix.  Probably a safe
 
867
  // bet.
 
868
  static int FCounter = -1;
 
869
  if (FCounter < 0) {
 
870
    // Give arbitrary initial seed.
 
871
    // FIXME: We should use sys::fs::unique_file() in future.
 
872
    LARGE_INTEGER cnt64;
 
873
    DWORD x = GetCurrentProcessId();
 
874
    x = (x << 16) | (x >> 16);
 
875
    if (QueryPerformanceCounter(&cnt64))    // RDTSC
 
876
      x ^= cnt64.HighPart ^ cnt64.LowPart;
 
877
    FCounter = x % 1000000;
 
878
  }
 
879
  do {
 
880
    sprintf(FNBuffer+offset, "-%06u", FCounter);
 
881
    if (++FCounter > 999999)
 
882
      FCounter = 0;
 
883
    path = FNBuffer;
 
884
  } while (!fs::exists(path, Exists) && Exists);
 
885
  return false;
 
886
}
 
887
 
 
888
bool
 
889
Path::createTemporaryFileOnDisk(bool reuse_current, std::string* ErrMsg) {
 
890
  // Make this into a unique file name
 
891
  makeUnique(reuse_current, ErrMsg);
 
892
 
 
893
  // Now go and create it
 
894
  HANDLE h = CreateFile(path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW,
 
895
                        FILE_ATTRIBUTE_NORMAL, NULL);
 
896
  if (h == INVALID_HANDLE_VALUE)
 
897
    return MakeErrMsg(ErrMsg, path + ": can't create file");
 
898
 
 
899
  CloseHandle(h);
 
900
  return false;
 
901
}
 
902
 
 
903
/// MapInFilePages - Not yet implemented on win32.
 
904
const char *Path::MapInFilePages(int FD, size_t FileSize, off_t Offset) {
 
905
  return 0;
 
906
}
 
907
 
 
908
/// MapInFilePages - Not yet implemented on win32.
 
909
void Path::UnMapFilePages(const char *Base, size_t FileSize) {
 
910
  assert(0 && "NOT IMPLEMENTED");
 
911
}
 
912
 
 
913
}
 
914
}