blob: 090112722385987493acbfb8802880bab7325cb9 [file] [log] [blame]
Greg Clayton60a63ae2011-02-08 17:49:02 +00001//===-- FileSpec.cpp --------------------------------------------*- 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
11#include "lldb/Host/File.h"
12
13#include <fcntl.h>
Greg Clayton80949d42011-02-09 21:12:40 +000014#include <stdarg.h>
Greg Clayton60a63ae2011-02-08 17:49:02 +000015
16#include "lldb/Core/Error.h"
Greg Claytonc08c4d32011-02-09 01:16:43 +000017#include "lldb/Host/Config.h"
Greg Claytond35305a2011-02-08 19:54:44 +000018#include "lldb/Host/FileSpec.h"
Greg Clayton60a63ae2011-02-08 17:49:02 +000019
20using namespace lldb;
21using namespace lldb_private;
22
Greg Clayton58928562011-02-09 01:08:52 +000023static const char *
24GetStreamOpenModeFromOptions (uint32_t options)
25{
26 if (options & File::eOpenOptionAppend)
27 {
28 if (options & File::eOpenOptionRead)
29 {
30 if (options & File::eOpenOptionCanCreateNewOnly)
31 return "a+x";
32 else
33 return "a+";
34 }
35 else if (options & File::eOpenOptionWrite)
36 {
37 if (options & File::eOpenOptionCanCreateNewOnly)
38 return "ax";
39 else
40 return "a";
41 }
42 }
43 else if (options & File::eOpenOptionRead && options & File::eOpenOptionWrite)
44 {
45 if (options & File::eOpenOptionCanCreate)
46 {
47 if (options & File::eOpenOptionCanCreateNewOnly)
48 return "w+x";
49 else
50 return "w+";
51 }
52 else
53 return "r+";
54 }
55 else if (options & File::eOpenOptionRead)
56 {
57 return "r";
58 }
59 else if (options & File::eOpenOptionWrite)
60 {
61 return "w";
62 }
63 return NULL;
64}
65
66int File::kInvalidDescriptor = -1;
67FILE * File::kInvalidStream = NULL;
68
Greg Clayton60a63ae2011-02-08 17:49:02 +000069File::File(const char *path, uint32_t options, uint32_t permissions) :
Greg Clayton58928562011-02-09 01:08:52 +000070 m_descriptor (kInvalidDescriptor),
71 m_stream (kInvalidStream),
72 m_options (0),
73 m_owned (false)
Greg Clayton60a63ae2011-02-08 17:49:02 +000074{
75 Open (path, options, permissions);
76}
77
Greg Clayton58928562011-02-09 01:08:52 +000078File::File (const File &rhs) :
79 m_descriptor (kInvalidDescriptor),
80 m_stream (kInvalidStream),
81 m_options (0),
82 m_owned (false)
83{
84 Duplicate (rhs);
85}
86
87
88File &
89File::operator = (const File &rhs)
90{
91 if (this != &rhs)
92 Duplicate (rhs);
93 return *this;
94}
95
Greg Clayton60a63ae2011-02-08 17:49:02 +000096File::~File()
97{
98 Close ();
99}
100
Greg Clayton58928562011-02-09 01:08:52 +0000101
102int
103File::GetDescriptor() const
104{
105 if (DescriptorIsValid())
106 return m_descriptor;
107
108 // Don't open the file descriptor if we don't need to, just get it from the
109 // stream if we have one.
110 if (StreamIsValid())
111 return fileno (m_stream);
112
113 // Invalid descriptor and invalid stream, return invalid descriptor.
114 return kInvalidDescriptor;
115}
116
117void
118File::SetDescriptor (int fd, bool transfer_ownership)
119{
120 if (IsValid())
121 Close();
122 m_descriptor = fd;
123 m_owned = transfer_ownership;
124}
125
126
127FILE *
128File::GetStream ()
129{
130 if (!StreamIsValid())
131 {
132 if (DescriptorIsValid())
133 {
134 const char *mode = GetStreamOpenModeFromOptions (m_options);
135 if (mode)
136 m_stream = ::fdopen (m_descriptor, mode);
137 }
138 }
139 return m_stream;
140}
141
142
143void
144File::SetStream (FILE *fh, bool transfer_ownership)
145{
146 if (IsValid())
147 Close();
148 m_stream = fh;
149 m_owned = transfer_ownership;
150}
151
152Error
153File::Duplicate (const File &rhs)
154{
155 Error error;
156 if (IsValid ())
157 Close();
158
159 if (rhs.DescriptorIsValid())
160 {
161 m_descriptor = ::fcntl(rhs.GetDescriptor(), F_DUPFD);
162 if (!DescriptorIsValid())
163 error.SetErrorToErrno();
164 else
165 {
166 m_options = rhs.m_options;
167 m_owned = true;
168 }
169 }
170 else
171 {
172 error.SetErrorString ("invalid file to duplicate");
173 }
174 return error;
175}
176
Greg Clayton60a63ae2011-02-08 17:49:02 +0000177Error
178File::Open (const char *path, uint32_t options, uint32_t permissions)
179{
180 Error error;
181 if (IsValid())
182 Close ();
183
184 int oflag = 0;
185 if (options & eOpenOptionRead &&
186 options & eOpenOptionWrite )
187 oflag |= O_RDWR;
188 else if (options & eOpenOptionRead)
189 oflag |= O_RDONLY;
190 else if (options & eOpenOptionWrite)
191 oflag |= O_WRONLY;
192
193 if (options & eOpenOptionNonBlocking)
194 oflag |= O_NONBLOCK;
195
196 if (options & eOpenOptionAppend)
197 oflag |= O_APPEND;
Greg Clayton58928562011-02-09 01:08:52 +0000198 else
199 oflag |= O_TRUNC;
Greg Clayton60a63ae2011-02-08 17:49:02 +0000200
201 if (options & eOpenOptionCanCreate)
202 oflag |= O_CREAT;
203
204 if (options & eOpenOptionCanCreateNewOnly)
205 oflag |= O_CREAT | O_EXCL;
206
Greg Clayton60a63ae2011-02-08 17:49:02 +0000207 mode_t mode = 0;
208 if (permissions & ePermissionsUserRead) mode |= S_IRUSR;
209 if (permissions & ePermissionsUserWrite) mode |= S_IWUSR;
210 if (permissions & ePermissionsUserExecute) mode |= S_IXUSR;
211 if (permissions & ePermissionsGroupRead) mode |= S_IRGRP;
212 if (permissions & ePermissionsGroupWrite) mode |= S_IWGRP;
213 if (permissions & ePermissionsGroupExecute) mode |= S_IXGRP;
214 if (permissions & ePermissionsWorldRead) mode |= S_IROTH;
215 if (permissions & ePermissionsWorldWrite) mode |= S_IWOTH;
216 if (permissions & ePermissionsWorldExecute) mode |= S_IXOTH;
217
Greg Clayton58928562011-02-09 01:08:52 +0000218 m_descriptor = ::open(path, oflag, mode);
219 if (!DescriptorIsValid())
Greg Clayton60a63ae2011-02-08 17:49:02 +0000220 error.SetErrorToErrno();
Greg Clayton58928562011-02-09 01:08:52 +0000221 else
222 m_owned = true;
Greg Clayton60a63ae2011-02-08 17:49:02 +0000223
224 return error;
225}
226
227Error
228File::Close ()
229{
230 Error error;
231 if (IsValid ())
232 {
Greg Clayton58928562011-02-09 01:08:52 +0000233 if (m_owned)
234 {
235 if (StreamIsValid())
236 {
237 if (::fclose (m_stream) == EOF)
238 error.SetErrorToErrno();
239 }
240
241 if (DescriptorIsValid())
242 {
243 if (::close (m_descriptor) != 0)
244 error.SetErrorToErrno();
245 }
246 }
247 m_descriptor = kInvalidDescriptor;
248 m_stream = kInvalidStream;
249 m_options = 0;
250 m_owned = false;
Greg Clayton60a63ae2011-02-08 17:49:02 +0000251 }
252 return error;
253}
Greg Clayton882ef052011-02-08 19:10:53 +0000254
255
256Error
257File::GetFileSpec (FileSpec &file_spec) const
258{
259 Error error;
Greg Claytonc08c4d32011-02-09 01:16:43 +0000260#ifdef LLDB_CONFIG_FCNTL_GETPATH_SUPPORTED
Greg Clayton882ef052011-02-08 19:10:53 +0000261 if (IsValid ())
262 {
263 char path[PATH_MAX];
Greg Clayton58928562011-02-09 01:08:52 +0000264 if (::fcntl(GetDescriptor(), F_GETPATH, path) == -1)
Greg Clayton882ef052011-02-08 19:10:53 +0000265 error.SetErrorToErrno();
266 else
267 file_spec.SetFile (path, false);
268 }
269 else
Greg Claytonc08c4d32011-02-09 01:16:43 +0000270 {
Greg Clayton882ef052011-02-08 19:10:53 +0000271 error.SetErrorString("invalid file handle");
Greg Claytonc08c4d32011-02-09 01:16:43 +0000272 }
Greg Clayton419144b2011-02-09 07:19:18 +0000273#elif defined(__linux__)
274 char proc[64];
275 char path[PATH_MAX];
276 if (::snprintf(proc, sizeof(proc), "/proc/self/fd/%d", GetDescriptor()) < 0)
277 error.SetErrorString ("Cannot resolve file descriptor\n");
278 else
279 {
280 ssize_t len;
281 if ((len = ::readlink(proc, path, sizeof(path) - 1)) == -1)
282 error.SetErrorToErrno();
283 else
284 {
285 path[len] = '\0';
286 file_spec.SetFile (path, false);
287 }
288 }
Greg Claytonc08c4d32011-02-09 01:16:43 +0000289#else
Greg Clayton419144b2011-02-09 07:19:18 +0000290 error.SetErrorString ("File::GetFileSpec is not supported on this platform");
Greg Claytonc08c4d32011-02-09 01:16:43 +0000291#endif
Greg Clayton882ef052011-02-08 19:10:53 +0000292
293 if (error.Fail())
294 file_spec.Clear();
295 return error;
296}
297
298Error
299File::SeekFromStart (off_t& offset)
300{
301 Error error;
Greg Clayton58928562011-02-09 01:08:52 +0000302 if (DescriptorIsValid())
Greg Clayton882ef052011-02-08 19:10:53 +0000303 {
Greg Clayton58928562011-02-09 01:08:52 +0000304 offset = ::lseek (m_descriptor, offset, SEEK_SET);
Greg Clayton882ef052011-02-08 19:10:53 +0000305
306 if (offset == -1)
307 error.SetErrorToErrno();
308 }
309 else
310 {
311 error.SetErrorString("invalid file handle");
312 }
313 return error;
314}
315
316Error
317File::SeekFromCurrent (off_t& offset)
318{
319 Error error;
Greg Clayton58928562011-02-09 01:08:52 +0000320 if (DescriptorIsValid())
Greg Clayton882ef052011-02-08 19:10:53 +0000321 {
Greg Clayton58928562011-02-09 01:08:52 +0000322 offset = ::lseek (m_descriptor, offset, SEEK_CUR);
Greg Clayton882ef052011-02-08 19:10:53 +0000323
324 if (offset == -1)
325 error.SetErrorToErrno();
326 }
327 else
328 {
329 error.SetErrorString("invalid file handle");
330 }
331 return error;
332}
333
334Error
335File::SeekFromEnd (off_t& offset)
336{
337 Error error;
Greg Clayton58928562011-02-09 01:08:52 +0000338 if (DescriptorIsValid())
Greg Clayton882ef052011-02-08 19:10:53 +0000339 {
Greg Clayton58928562011-02-09 01:08:52 +0000340 offset = ::lseek (m_descriptor, offset, SEEK_CUR);
Greg Clayton882ef052011-02-08 19:10:53 +0000341
342 if (offset == -1)
343 error.SetErrorToErrno();
344 }
345 else
346 {
347 error.SetErrorString("invalid file handle");
348 }
349 return error;
350}
351
352Error
Greg Clayton58928562011-02-09 01:08:52 +0000353File::Flush ()
354{
355 Error error;
356 if (StreamIsValid())
357 {
358 if (::fflush (m_stream) == EOF)
359 error.SetErrorToErrno();
360 }
361 else if (!DescriptorIsValid())
362 {
363 error.SetErrorString("invalid file handle");
364 }
365 return error;
366}
367
368
369Error
Greg Clayton882ef052011-02-08 19:10:53 +0000370File::Sync ()
371{
372 Error error;
Greg Clayton58928562011-02-09 01:08:52 +0000373 if (DescriptorIsValid())
Greg Clayton882ef052011-02-08 19:10:53 +0000374 {
Greg Clayton58928562011-02-09 01:08:52 +0000375 if (::fsync (m_descriptor) == -1)
Greg Clayton882ef052011-02-08 19:10:53 +0000376 error.SetErrorToErrno();
377 }
378 else
379 {
380 error.SetErrorString("invalid file handle");
381 }
382 return error;
383}
Greg Claytond35305a2011-02-08 19:54:44 +0000384
Greg Clayton60a63ae2011-02-08 17:49:02 +0000385Error
386File::Read (void *buf, size_t &num_bytes)
387{
388 Error error;
Greg Clayton58928562011-02-09 01:08:52 +0000389 if (DescriptorIsValid())
Greg Clayton60a63ae2011-02-08 17:49:02 +0000390 {
Greg Clayton58928562011-02-09 01:08:52 +0000391 ssize_t bytes_read = ::read (m_descriptor, buf, num_bytes);
Greg Clayton60a63ae2011-02-08 17:49:02 +0000392 if (bytes_read == -1)
393 {
394 error.SetErrorToErrno();
395 num_bytes = 0;
396 }
397 else
398 num_bytes = bytes_read;
399 }
Greg Clayton58928562011-02-09 01:08:52 +0000400 else if (StreamIsValid())
401 {
402 size_t bytes_read = ::fread (buf, 1, num_bytes, m_stream);
403 if (bytes_read == 0)
404 {
405 if (::feof(m_stream))
406 error.SetErrorString ("feof");
407 else if (::ferror (m_stream))
408 error.SetErrorString ("ferror");
409 num_bytes = 0;
410 }
411 else
412 num_bytes = bytes_read;
413 }
Greg Clayton60a63ae2011-02-08 17:49:02 +0000414 else
415 {
416 num_bytes = 0;
417 error.SetErrorString("invalid file handle");
418 }
419 return error;
420}
421
422Error
423File::Write (const void *buf, size_t &num_bytes)
424{
425 Error error;
Greg Clayton58928562011-02-09 01:08:52 +0000426 if (DescriptorIsValid())
Greg Clayton60a63ae2011-02-08 17:49:02 +0000427 {
Greg Clayton58928562011-02-09 01:08:52 +0000428 ssize_t bytes_written = ::write (m_descriptor, buf, num_bytes);
Greg Clayton60a63ae2011-02-08 17:49:02 +0000429 if (bytes_written == -1)
430 {
431 error.SetErrorToErrno();
432 num_bytes = 0;
433 }
434 else
435 num_bytes = bytes_written;
436 }
Greg Clayton58928562011-02-09 01:08:52 +0000437 else if (StreamIsValid())
438 {
439 size_t bytes_written = ::fwrite (buf, 1, num_bytes, m_stream);
440 if (bytes_written == 0)
441 {
442 if (::feof(m_stream))
443 error.SetErrorString ("feof");
444 else if (::ferror (m_stream))
445 error.SetErrorString ("ferror");
446 num_bytes = 0;
447 }
448 else
449 num_bytes = bytes_written;
450
451 }
Greg Clayton60a63ae2011-02-08 17:49:02 +0000452 else
453 {
454 num_bytes = 0;
455 error.SetErrorString("invalid file handle");
456 }
457 return error;
458}
459
Greg Claytond35305a2011-02-08 19:54:44 +0000460
461Error
462File::Read (void *buf, size_t &num_bytes, off_t &offset)
463{
464 Error error;
Greg Clayton58928562011-02-09 01:08:52 +0000465 int fd = GetDescriptor();
466 if (fd != kInvalidDescriptor)
Greg Claytond35305a2011-02-08 19:54:44 +0000467 {
Greg Clayton58928562011-02-09 01:08:52 +0000468 ssize_t bytes_read = ::pread (fd, buf, num_bytes, offset);
Greg Claytond35305a2011-02-08 19:54:44 +0000469 if (bytes_read < 0)
470 {
471 num_bytes = 0;
472 error.SetErrorToErrno();
473 }
474 else
475 {
476 offset += bytes_read;
477 num_bytes = bytes_read;
478 }
479 }
480 else
481 {
482 num_bytes = 0;
483 error.SetErrorString("invalid file handle");
484 }
485 return error;
486}
487
488Error
489File::Write (const void *buf, size_t &num_bytes, off_t &offset)
490{
491 Error error;
Greg Clayton58928562011-02-09 01:08:52 +0000492 int fd = GetDescriptor();
493 if (fd != kInvalidDescriptor)
Greg Claytond35305a2011-02-08 19:54:44 +0000494 {
Greg Clayton58928562011-02-09 01:08:52 +0000495 ssize_t bytes_written = ::pwrite (m_descriptor, buf, num_bytes, offset);
Greg Claytond35305a2011-02-08 19:54:44 +0000496 if (bytes_written < 0)
497 {
498 num_bytes = 0;
499 error.SetErrorToErrno();
500 }
501 else
502 {
503 offset += bytes_written;
504 num_bytes = bytes_written;
505 }
506 }
507 else
508 {
509 num_bytes = 0;
510 error.SetErrorString("invalid file handle");
511 }
512 return error;
513}
514
Greg Clayton58928562011-02-09 01:08:52 +0000515//------------------------------------------------------------------
516// Print some formatted output to the stream.
517//------------------------------------------------------------------
518int
519File::Printf (const char *format, ...)
520{
521 va_list args;
522 va_start (args, format);
523 int result = PrintfVarArg (format, args);
524 va_end (args);
525 return result;
526}
Greg Claytond35305a2011-02-08 19:54:44 +0000527
Greg Clayton58928562011-02-09 01:08:52 +0000528//------------------------------------------------------------------
529// Print some formatted output to the stream.
530//------------------------------------------------------------------
531int
532File::PrintfVarArg (const char *format, va_list args)
533{
534 int result = 0;
535 if (DescriptorIsValid())
536 {
537 char *s = NULL;
538 result = vasprintf(&s, format, args);
539 if (s != NULL)
540 {
541 if (result > 0)
542 {
543 size_t s_len = result;
544 Write (s, s_len);
545 result = s_len;
546 }
547 free (s);
548 }
549 }
550 else if (StreamIsValid())
551 {
552 result = ::vfprintf (m_stream, format, args);
553 }
554 return result;
555}