• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /*--------------------------------------------------------------------*/
3 /*--- File- and socket-related libc stuff.            m_libcfile.c ---*/
4 /*--------------------------------------------------------------------*/
5 
6 /*
7    This file is part of Valgrind, a dynamic binary instrumentation
8    framework.
9 
10    Copyright (C) 2000-2013 Julian Seward
11       jseward@acm.org
12 
13    This program is free software; you can redistribute it and/or
14    modify it under the terms of the GNU General Public License as
15    published by the Free Software Foundation; either version 2 of the
16    License, or (at your option) any later version.
17 
18    This program is distributed in the hope that it will be useful, but
19    WITHOUT ANY WARRANTY; without even the implied warranty of
20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21    General Public License for more details.
22 
23    You should have received a copy of the GNU General Public License
24    along with this program; if not, write to the Free Software
25    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
26    02111-1307, USA.
27 
28    The GNU General Public License is contained in the file COPYING.
29 */
30 
31 #include "pub_core_basics.h"
32 #include "pub_core_vki.h"
33 #include "pub_core_vkiscnums.h"
34 #include "pub_core_debuglog.h"
35 #include "pub_core_libcbase.h"
36 #include "pub_core_libcassert.h"
37 #include "pub_core_libcfile.h"
38 #include "pub_core_libcprint.h"     // VG_(sprintf)
39 #include "pub_core_libcproc.h"      // VG_(getpid), VG_(getppid)
40 #include "pub_core_xarray.h"
41 #include "pub_core_clientstate.h"   // VG_(fd_hard_limit)
42 #include "pub_core_syscall.h"
43 
44 /* IMPORTANT: on Darwin it is essential to use the _nocancel versions
45    of syscalls rather than the vanilla version, if a _nocancel version
46    is available.  See docs/internals/Darwin-notes.txt for the reason
47    why. */
48 
49 /* ---------------------------------------------------------------------
50    File stuff
51    ------------------------------------------------------------------ */
52 
fd_exists(Int fd)53 static inline Bool fd_exists(Int fd)
54 {
55    struct vg_stat st;
56    return VG_(fstat)(fd, &st) == 0;
57 }
58 
59 /* Move an fd into the Valgrind-safe range */
VG_(safe_fd)60 Int VG_(safe_fd)(Int oldfd)
61 {
62    Int newfd;
63 
64    vg_assert(VG_(fd_hard_limit) != -1);
65 
66    newfd = VG_(fcntl)(oldfd, VKI_F_DUPFD, VG_(fd_hard_limit));
67    if (newfd != -1)
68       VG_(close)(oldfd);
69 
70    /* Set the close-on-exec flag for this fd. */
71    VG_(fcntl)(newfd, VKI_F_SETFD, VKI_FD_CLOEXEC);
72 
73    vg_assert(newfd >= VG_(fd_hard_limit));
74    return newfd;
75 }
76 
77 /* Given a file descriptor, attempt to deduce its filename.  To do
78    this, we use /proc/self/fd/<FD>.  If this doesn't point to a file,
79    or if it doesn't exist, we return False. */
VG_(resolve_filename)80 Bool VG_(resolve_filename) ( Int fd, HChar* buf, Int n_buf )
81 {
82 #  if defined(VGO_linux)
83    HChar tmp[64];
84    VG_(sprintf)(tmp, "/proc/self/fd/%d", fd);
85    VG_(memset)(buf, 0, n_buf);
86    if (VG_(readlink)(tmp, buf, n_buf) > 0 && buf[0] == '/')
87       return True;
88    else
89       return False;
90 
91 #  elif defined(VGO_darwin)
92    HChar tmp[VKI_MAXPATHLEN+1];
93    if (0 == VG_(fcntl)(fd, VKI_F_GETPATH, (UWord)tmp)) {
94       if (n_buf > 0) {
95          VG_(strncpy)( buf, tmp, n_buf < sizeof(tmp) ? n_buf : sizeof(tmp) );
96          buf[n_buf-1] = 0;
97       }
98       if (tmp[0] == '/') return True;
99    }
100    return False;
101 
102 #  else
103 #     error Unknown OS
104 #  endif
105 }
106 
VG_(mknod)107 SysRes VG_(mknod) ( const HChar* pathname, Int mode, UWord dev )
108 {
109 #  if defined(VGP_arm64_linux)
110    /* ARM64 wants to use __NR_mknodat rather than __NR_mknod. */
111    SysRes res = VG_(do_syscall4)(__NR_mknodat,
112                                  VKI_AT_FDCWD, (UWord)pathname, mode, dev);
113 #  elif defined(VGO_linux) || defined(VGO_darwin)
114    SysRes res = VG_(do_syscall3)(__NR_mknod,
115                                  (UWord)pathname, mode, dev);
116 #  else
117 #    error Unknown OS
118 #  endif
119    return res;
120 }
121 
VG_(open)122 SysRes VG_(open) ( const HChar* pathname, Int flags, Int mode )
123 {
124 #  if defined(VGP_arm64_linux)
125    /* ARM64 wants to use __NR_openat rather than __NR_open. */
126    SysRes res = VG_(do_syscall4)(__NR_openat,
127                                  VKI_AT_FDCWD, (UWord)pathname, flags, mode);
128 #  elif defined(VGO_linux)
129    SysRes res = VG_(do_syscall3)(__NR_open,
130                                  (UWord)pathname, flags, mode);
131 #  elif defined(VGO_darwin)
132    SysRes res = VG_(do_syscall3)(__NR_open_nocancel,
133                                  (UWord)pathname, flags, mode);
134 #  else
135 #    error Unknown OS
136 #  endif
137    return res;
138 }
139 
VG_(fd_open)140 Int VG_(fd_open) (const HChar* pathname, Int flags, Int mode)
141 {
142    SysRes sr;
143    sr = VG_(open) (pathname, flags, mode);
144    if (sr_isError (sr))
145       return -1;
146    else
147       return sr_Res (sr);
148 }
149 
VG_(close)150 void VG_(close) ( Int fd )
151 {
152    /* Hmm.  Return value is not checked.  That's uncool. */
153 #  if defined(VGO_linux)
154    (void)VG_(do_syscall1)(__NR_close, fd);
155 #  elif defined(VGO_darwin)
156    (void)VG_(do_syscall1)(__NR_close_nocancel, fd);
157 #  else
158 #    error Unknown OS
159 #  endif
160 }
161 
VG_(read)162 Int VG_(read) ( Int fd, void* buf, Int count)
163 {
164    Int    ret;
165 #  if defined(VGO_linux)
166    SysRes res = VG_(do_syscall3)(__NR_read, fd, (UWord)buf, count);
167 #  elif defined(VGO_darwin)
168    SysRes res = VG_(do_syscall3)(__NR_read_nocancel, fd, (UWord)buf, count);
169 #  else
170 #    error Unknown OS
171 #  endif
172    if (sr_isError(res)) {
173       ret = - (Int)(Word)sr_Err(res);
174       vg_assert(ret < 0);
175    } else {
176       ret = (Int)(Word)sr_Res(res);
177       vg_assert(ret >= 0);
178    }
179    return ret;
180 }
181 
VG_(write)182 Int VG_(write) ( Int fd, const void* buf, Int count)
183 {
184    Int    ret;
185 #  if defined(VGO_linux)
186    SysRes res = VG_(do_syscall3)(__NR_write, fd, (UWord)buf, count);
187 #  elif defined(VGO_darwin)
188    SysRes res = VG_(do_syscall3)(__NR_write_nocancel, fd, (UWord)buf, count);
189 #  else
190 #    error "Unknown OS"
191 #  endif
192    if (sr_isError(res)) {
193       ret = - (Int)(Word)sr_Err(res);
194       vg_assert(ret < 0);
195    } else {
196       ret = (Int)(Word)sr_Res(res);
197       vg_assert(ret >= 0);
198    }
199    return ret;
200 }
201 
202 
VG_(pipe)203 Int VG_(pipe) ( Int fd[2] )
204 {
205 #  if defined(VGP_mips32_linux) || defined(VGP_mips64_linux)
206    /* __NR_pipe has a strange return convention on mips32-linux. */
207    SysRes res = VG_(do_syscall1)(__NR_pipe, (UWord)fd);
208    if (!sr_isError(res)) {
209       fd[0] = (Int)sr_Res(res);
210       fd[1] = (Int)sr_ResEx(res);
211       return 0;
212    } else {
213       return -1;
214    }
215 #  elif defined(VGP_arm64_linux)
216    SysRes res = VG_(do_syscall2)(__NR_pipe2, (UWord)fd, 0);
217    return sr_isError(res) ? -1 : 0;
218 #  elif defined(VGO_linux)
219    SysRes res = VG_(do_syscall1)(__NR_pipe, (UWord)fd);
220    return sr_isError(res) ? -1 : 0;
221 #  elif defined(VGO_darwin)
222    /* __NR_pipe is UX64, so produces a double-word result */
223    SysRes res = VG_(do_syscall0)(__NR_pipe);
224    if (!sr_isError(res)) {
225       fd[0] = (Int)sr_Res(res);
226       fd[1] = (Int)sr_ResHI(res);
227    }
228    return sr_isError(res) ? -1 : 0;
229 #  else
230 #    error "Unknown OS"
231 #  endif
232 }
233 
VG_(lseek)234 Off64T VG_(lseek) ( Int fd, Off64T offset, Int whence )
235 {
236 #  if defined(VGO_linux) || defined(VGP_amd64_darwin)
237 #  if defined(__NR__llseek)
238    Off64T result;
239    SysRes res = VG_(do_syscall5)(__NR__llseek, fd,
240                                  offset >> 32, offset & 0xffffffff,
241                                  (UWord)&result, whence);
242    return sr_isError(res) ? (-1) : result;
243 #  else
244    SysRes res = VG_(do_syscall3)(__NR_lseek, fd, offset, whence);
245    vg_assert(sizeof(Off64T) == sizeof(Word));
246    return sr_isError(res) ? (-1) : sr_Res(res);
247 #  endif
248 #  elif defined(VGP_x86_darwin)
249    SysRes res = VG_(do_syscall4)(__NR_lseek, fd,
250                                  offset & 0xffffffff, offset >> 32, whence);
251    return sr_isError(res) ? (-1) : sr_Res(res);
252 #  else
253 #    error "Unknown plat"
254 #  endif
255    /* if you change the error-reporting conventions of this, also
256       change all usage points. */
257 }
258 
259 
260 /* stat/fstat support.  It's uggerly.  We have impedance-match into a
261    'struct vg_stat' in order to have a single structure that callers
262    can use consistently on all platforms. */
263 
264 #define TRANSLATE_TO_vg_stat(_p_vgstat, _p_vkistat) \
265    do { \
266       (_p_vgstat)->dev        = (ULong)( (_p_vkistat)->st_dev ); \
267       (_p_vgstat)->ino        = (ULong)( (_p_vkistat)->st_ino ); \
268       (_p_vgstat)->nlink      = (ULong)( (_p_vkistat)->st_nlink ); \
269       (_p_vgstat)->mode       = (UInt) ( (_p_vkistat)->st_mode ); \
270       (_p_vgstat)->uid        = (UInt) ( (_p_vkistat)->st_uid ); \
271       (_p_vgstat)->gid        = (UInt) ( (_p_vkistat)->st_gid ); \
272       (_p_vgstat)->rdev       = (ULong)( (_p_vkistat)->st_rdev ); \
273       (_p_vgstat)->size       = (Long) ( (_p_vkistat)->st_size ); \
274       (_p_vgstat)->blksize    = (ULong)( (_p_vkistat)->st_blksize ); \
275       (_p_vgstat)->blocks     = (ULong)( (_p_vkistat)->st_blocks ); \
276       (_p_vgstat)->atime      = (ULong)( (_p_vkistat)->st_atime ); \
277       (_p_vgstat)->atime_nsec = (ULong)( (_p_vkistat)->st_atime_nsec ); \
278       (_p_vgstat)->mtime      = (ULong)( (_p_vkistat)->st_mtime ); \
279       (_p_vgstat)->mtime_nsec = (ULong)( (_p_vkistat)->st_mtime_nsec ); \
280       (_p_vgstat)->ctime      = (ULong)( (_p_vkistat)->st_ctime ); \
281       (_p_vgstat)->ctime_nsec = (ULong)( (_p_vkistat)->st_ctime_nsec ); \
282    } while (0)
283 
VG_(stat)284 SysRes VG_(stat) ( const HChar* file_name, struct vg_stat* vgbuf )
285 {
286    SysRes res;
287    VG_(memset)(vgbuf, 0, sizeof(*vgbuf));
288 
289 #  if defined(VGO_linux) || defined(VGO_darwin)
290    /* First try with stat64.  If that doesn't work out, fall back to
291       the vanilla version. */
292 #  if defined(__NR_stat64)
293    { struct vki_stat64 buf64;
294      res = VG_(do_syscall2)(__NR_stat64, (UWord)file_name, (UWord)&buf64);
295      if (!(sr_isError(res) && sr_Err(res) == VKI_ENOSYS)) {
296         /* Success, or any failure except ENOSYS */
297         if (!sr_isError(res))
298            TRANSLATE_TO_vg_stat(vgbuf, &buf64);
299         return res;
300      }
301    }
302 #  endif /* defined(__NR_stat64) */
303    /* This is the fallback ("vanilla version"). */
304    { struct vki_stat buf;
305 #    if defined(VGP_arm64_linux)
306      res = VG_(do_syscall3)(__NR3264_fstatat, VKI_AT_FDCWD,
307                                               (UWord)file_name, (UWord)&buf);
308 #    else
309      res = VG_(do_syscall2)(__NR_stat, (UWord)file_name, (UWord)&buf);
310 #    endif
311      if (!sr_isError(res))
312         TRANSLATE_TO_vg_stat(vgbuf, &buf);
313      return res;
314    }
315 
316 #  else
317 #    error Unknown OS
318 #  endif
319 }
320 
VG_(fstat)321 Int VG_(fstat) ( Int fd, struct vg_stat* vgbuf )
322 {
323    SysRes res;
324    VG_(memset)(vgbuf, 0, sizeof(*vgbuf));
325 
326 #  if defined(VGO_linux)  ||  defined(VGO_darwin)
327    /* First try with fstat64.  If that doesn't work out, fall back to
328       the vanilla version. */
329 #  if defined(__NR_fstat64)
330    { struct vki_stat64 buf64;
331      res = VG_(do_syscall2)(__NR_fstat64, (UWord)fd, (UWord)&buf64);
332      if (!(sr_isError(res) && sr_Err(res) == VKI_ENOSYS)) {
333         /* Success, or any failure except ENOSYS */
334         if (!sr_isError(res))
335            TRANSLATE_TO_vg_stat(vgbuf, &buf64);
336         return sr_isError(res) ? (-1) : 0;
337      }
338    }
339 #  endif /* if defined(__NR_fstat64) */
340    { struct vki_stat buf;
341      res = VG_(do_syscall2)(__NR_fstat, (UWord)fd, (UWord)&buf);
342      if (!sr_isError(res))
343         TRANSLATE_TO_vg_stat(vgbuf, &buf);
344      return sr_isError(res) ? (-1) : 0;
345    }
346 
347 #  else
348 #    error Unknown OS
349 #  endif
350 }
351 
352 #undef TRANSLATE_TO_vg_stat
353 
354 
VG_(fsize)355 Long VG_(fsize) ( Int fd )
356 {
357    struct vg_stat buf;
358    Int res = VG_(fstat)( fd, &buf );
359    return (res == -1) ? (-1LL) : buf.size;
360 }
361 
VG_(getxattr)362 SysRes VG_(getxattr) ( const HChar* file_name, const HChar* attr_name, Addr attr_value, SizeT attr_value_len )
363 {
364    SysRes res;
365 #if defined(VGO_linux)
366    res = VG_(do_syscall4)(__NR_getxattr, (UWord)file_name, (UWord)attr_name,
367                           attr_value, attr_value_len);
368 #else
369    res = VG_(mk_SysRes_Error)(VKI_ENOSYS);
370 #endif
371    return res;
372 }
373 
VG_(is_dir)374 Bool VG_(is_dir) ( const HChar* f )
375 {
376    struct vg_stat buf;
377    SysRes res = VG_(stat)(f, &buf);
378    return sr_isError(res) ? False
379                       : VKI_S_ISDIR(buf.mode) ? True : False;
380 }
381 
VG_(dup)382 SysRes VG_(dup) ( Int oldfd )
383 {
384    return VG_(do_syscall1)(__NR_dup, oldfd);
385 }
386 
VG_(dup2)387 SysRes VG_(dup2) ( Int oldfd, Int newfd )
388 {
389 #  if defined(VGO_linux) || defined(VGO_darwin)
390    return VG_(do_syscall2)(__NR_dup2, oldfd, newfd);
391 #  else
392 #    error Unknown OS
393 #  endif
394 }
395 
396 /* Returns -1 on error. */
VG_(fcntl)397 Int VG_(fcntl) ( Int fd, Int cmd, Addr arg )
398 {
399 #  if defined(VGO_linux)
400    SysRes res = VG_(do_syscall3)(__NR_fcntl, fd, cmd, arg);
401 #  elif defined(VGO_darwin)
402    SysRes res = VG_(do_syscall3)(__NR_fcntl_nocancel, fd, cmd, arg);
403 #  else
404 #    error "Unknown OS"
405 #  endif
406    return sr_isError(res) ? -1 : sr_Res(res);
407 }
408 
VG_(rename)409 Int VG_(rename) ( const HChar* old_name, const HChar* new_name )
410 {
411    SysRes res = VG_(do_syscall2)(__NR_rename, (UWord)old_name, (UWord)new_name);
412    return sr_isError(res) ? (-1) : 0;
413 }
414 
VG_(unlink)415 Int VG_(unlink) ( const HChar* file_name )
416 {
417 #  if defined(VGP_arm64_linux)
418    SysRes res = VG_(do_syscall2)(__NR_unlinkat, VKI_AT_FDCWD,
419                                                 (UWord)file_name);
420 #  else
421    SysRes res = VG_(do_syscall1)(__NR_unlink, (UWord)file_name);
422 #  endif
423    return sr_isError(res) ? (-1) : 0;
424 }
425 
426 /* The working directory at startup.  AIX doesn't provide an easy
427    system call to do getcwd, but fortunately we don't need arbitrary
428    getcwd support.  All that is really needed is to note the cwd at
429    process startup.  Hence VG_(record_startup_wd) notes it (in a
430    platform dependent way) and VG_(get_startup_wd) produces the noted
431    value.  Hence: */
432 static HChar startup_wd[VKI_PATH_MAX];
433 static Bool  startup_wd_acquired = False;
434 
435 /* Record the process' working directory at startup.  Is intended to
436    be called exactly once, at startup, before the working directory
437    changes.  Return True for success, False for failure, so that the
438    caller can bomb out suitably without creating module cycles if
439    there is a problem. */
VG_(record_startup_wd)440 Bool VG_(record_startup_wd) ( void )
441 {
442    const Int szB = sizeof(startup_wd);
443    vg_assert(!startup_wd_acquired);
444    vg_assert(szB >= 512 && szB <= 16384/*let's say*/); /* stay sane */
445    VG_(memset)(startup_wd, 0, szB);
446 #  if defined(VGO_linux)
447    /* Simple: just ask the kernel */
448    { SysRes res
449         = VG_(do_syscall2)(__NR_getcwd, (UWord)startup_wd, szB-1);
450      vg_assert(startup_wd[szB-1] == 0);
451      if (sr_isError(res)) {
452         return False;
453      } else {
454         startup_wd_acquired = True;
455         return True;
456      }
457    }
458 #  elif defined(VGO_darwin)
459    /* We can't ask the kernel, so instead rely on launcher-*.c to
460       tell us the startup path.  Note the env var is keyed to the
461       parent's PID, not ours, since our parent is the launcher
462       process. */
463    { HChar  envvar[100];
464      HChar* wd = NULL;
465      VG_(memset)(envvar, 0, sizeof(envvar));
466      VG_(sprintf)(envvar, "VALGRIND_STARTUP_PWD_%d_XYZZY",
467                           (Int)VG_(getppid)());
468      wd = VG_(getenv)( envvar );
469      if (wd == NULL || (1+VG_(strlen)(wd) >= szB))
470         return False;
471      VG_(strncpy_safely)(startup_wd, wd, szB);
472      vg_assert(startup_wd[szB-1] == 0);
473      startup_wd_acquired = True;
474      return True;
475    }
476 #  else
477 #    error Unknown OS
478 #  endif
479 }
480 
481 /* Copy the previously acquired startup_wd into buf[0 .. size-1],
482    or return False if buf isn't big enough. */
VG_(get_startup_wd)483 Bool VG_(get_startup_wd) ( HChar* buf, SizeT size )
484 {
485    vg_assert(startup_wd_acquired);
486    vg_assert(startup_wd[ sizeof(startup_wd)-1 ] == 0);
487    if (1+VG_(strlen)(startup_wd) >= size)
488       return False;
489    VG_(strncpy_safely)(buf, startup_wd, size);
490    return True;
491 }
492 
VG_(poll)493 SysRes VG_(poll) (struct vki_pollfd *fds, Int nfds, Int timeout)
494 {
495    SysRes res;
496 #  if defined(VGP_arm64_linux)
497    /* ARM64 wants to use __NR_ppoll rather than __NR_poll. */
498    struct vki_timespec timeout_ts;
499    if (timeout >= 0) {
500       timeout_ts.tv_sec = timeout / 1000;
501       timeout_ts.tv_nsec = ((long)timeout % 1000) * 1000000;
502    }
503    res = VG_(do_syscall4)(__NR_ppoll,
504                           (UWord)fds, nfds,
505                           (UWord)(timeout >= 0 ? &timeout_ts : NULL),
506                           (UWord)NULL);
507 #  elif defined(VGO_linux)
508    res = VG_(do_syscall3)(__NR_poll, (UWord)fds, nfds, timeout);
509 #  elif defined(VGO_darwin)
510    res = VG_(do_syscall3)(__NR_poll_nocancel, (UWord)fds, nfds, timeout);
511 #  else
512 #    error "Unknown OS"
513 #  endif
514    return res;
515 }
516 
517 
VG_(readlink)518 Int VG_(readlink) (const HChar* path, HChar* buf, UInt bufsiz)
519 {
520    SysRes res;
521    /* res = readlink( path, buf, bufsiz ); */
522 #  if defined(VGP_arm64_linux)
523    res = VG_(do_syscall4)(__NR_readlinkat, VKI_AT_FDCWD,
524                                            (UWord)path, (UWord)buf, bufsiz);
525 #  else
526    res = VG_(do_syscall3)(__NR_readlink, (UWord)path, (UWord)buf, bufsiz);
527 #  endif
528    return sr_isError(res) ? -1 : sr_Res(res);
529 }
530 
VG_(getdents)531 Int VG_(getdents) (Int fd, struct vki_dirent *dirp, UInt count)
532 {
533 #  if defined(VGO_linux)
534    SysRes res;
535    /* res = getdents( fd, dirp, count ); */
536    res = VG_(do_syscall3)(__NR_getdents, fd, (UWord)dirp, count);
537    return sr_isError(res) ? -1 : sr_Res(res);
538 #  elif defined(VGO_darwin)
539    I_die_here;
540 #  else
541 #    error "Unknown OS"
542 #  endif
543 }
544 
545 /* Check accessibility of a file.  Returns zero for access granted,
546    nonzero otherwise. */
VG_(access)547 Int VG_(access) ( const HChar* path, Bool irusr, Bool iwusr, Bool ixusr )
548 {
549 #  if defined(VGO_linux)
550    /* Very annoyingly, I cannot find any definition for R_OK et al in
551       the kernel interfaces.  Therefore I reluctantly resort to
552       hardwiring in these magic numbers that I determined by
553       experimentation. */
554 #  define VKI_R_OK 4
555 #  define VKI_W_OK 2
556 #  define VKI_X_OK 1
557 #  endif
558 
559    UWord w = (irusr ? VKI_R_OK : 0)
560              | (iwusr ? VKI_W_OK : 0)
561              | (ixusr ? VKI_X_OK : 0);
562 #  if defined(VGP_arm64_linux)
563    SysRes res = VG_(do_syscall3)(__NR_faccessat, VKI_AT_FDCWD, (UWord)path, w);
564 #  else
565    SysRes res = VG_(do_syscall2)(__NR_access, (UWord)path, w);
566 #  endif
567    return sr_isError(res) ? 1 : 0;
568 
569 #  if defined(VGO_linux)
570 #  undef VKI_R_OK
571 #  undef VKI_W_OK
572 #  undef VKI_X_OK
573 #  endif
574 }
575 
576 /*
577    Emulate the normal Unix permissions checking algorithm.
578 
579    If owner matches, then use the owner permissions, else
580    if group matches, then use the group permissions, else
581    use other permissions.
582 
583    Note that we can't deal properly with SUID/SGID.  By default
584    (allow_setuid == False), we refuse to run them (otherwise the
585    executable may misbehave if it doesn't have the permissions it
586    thinks it does).  However, the caller may indicate that setuid
587    executables are allowed, for example if we are going to exec them
588    but not trace into them (iow, client sys_execve when
589    clo_trace_children == False).
590 
591    If VKI_EACCES is returned (iow, permission was refused), then
592    *is_setuid is set to True iff permission was refused because the
593    executable is setuid.
594 */
595 /* returns: 0 = success, non-0 is failure */
VG_(check_executable)596 Int VG_(check_executable)(/*OUT*/Bool* is_setuid,
597                           const HChar* f, Bool allow_setuid)
598 {
599    struct vg_stat st;
600    SysRes res = VG_(stat)(f, &st);
601 
602    if (is_setuid)
603       *is_setuid = False;
604 
605    if (sr_isError(res)) {
606       return sr_Err(res);
607    }
608 
609    if ( (st.mode & (VKI_S_ISUID | VKI_S_ISGID)) && !allow_setuid ) {
610       if (is_setuid)
611          *is_setuid = True;
612       return VKI_EACCES;
613    }
614 
615    res = VG_(getxattr)(f, "security.capability", (Addr)0, 0);
616    if (!sr_isError(res) && !allow_setuid) {
617       if (is_setuid)
618          *is_setuid = True;
619       return VKI_EACCES;
620    }
621 
622    if (VG_(geteuid)() == st.uid) {
623       if (!(st.mode & VKI_S_IXUSR))
624          return VKI_EACCES;
625    } else {
626       Int grpmatch = 0;
627 
628       if (VG_(getegid)() == st.gid)
629 	 grpmatch = 1;
630       else {
631 	 UInt groups[32];
632 	 Int ngrp = VG_(getgroups)(32, groups);
633 	 Int i;
634          /* ngrp will be -1 if VG_(getgroups) failed. */
635          for (i = 0; i < ngrp; i++) {
636 	    if (groups[i] == st.gid) {
637 	       grpmatch = 1;
638 	       break;
639 	    }
640          }
641       }
642 
643       if (grpmatch) {
644 	 if (!(st.mode & VKI_S_IXGRP)) {
645             return VKI_EACCES;
646          }
647       } else if (!(st.mode & VKI_S_IXOTH)) {
648          return VKI_EACCES;
649       }
650    }
651 
652    return 0;
653 }
654 
VG_(pread)655 SysRes VG_(pread) ( Int fd, void* buf, Int count, OffT offset )
656 {
657    SysRes res;
658    // on 32 bits platforms, we receive a 32 bits OffT but
659    // we must extend it to pass a long long 64 bits.
660 #  if defined(VGP_x86_linux)
661    vg_assert(sizeof(OffT) == 4);
662    res = VG_(do_syscall5)(__NR_pread64, fd, (UWord)buf, count,
663                           offset, 0); // Little endian long long
664    return res;
665 #  elif defined(VGP_arm_linux)
666    vg_assert(sizeof(OffT) == 4);
667    res = VG_(do_syscall5)(__NR_pread64, fd, (UWord)buf, count,
668                           0, offset); // Big endian long long
669    return res;
670 #  elif defined(VGP_ppc32_linux)
671    vg_assert(sizeof(OffT) == 4);
672    res = VG_(do_syscall6)(__NR_pread64, fd, (UWord)buf, count,
673                           0, // Padding needed on PPC32
674                           0, offset); // Big endian long long
675    return res;
676 #  elif defined(VGP_mips32_linux) && (VKI_LITTLE_ENDIAN)
677    vg_assert(sizeof(OffT) == 4);
678    res = VG_(do_syscall6)(__NR_pread64, fd, (UWord)buf, count,
679                           0, offset, 0);
680    return res;
681 #  elif defined(VGP_mips32_linux) && (VKI_BIG_ENDIAN)
682    vg_assert(sizeof(OffT) == 4);
683    res = VG_(do_syscall6)(__NR_pread64, fd, (UWord)buf, count,
684                           0, 0, offset);
685    return res;
686 #  elif defined(VGP_amd64_linux) \
687       || defined(VGP_ppc64_linux) || defined(VGP_s390x_linux) \
688       || defined(VGP_mips64_linux) \
689       || defined(VGP_arm64_linux)
690    res = VG_(do_syscall4)(__NR_pread64, fd, (UWord)buf, count, offset);
691    return res;
692 #  elif defined(VGP_amd64_darwin)
693    vg_assert(sizeof(OffT) == 8);
694    res = VG_(do_syscall4)(__NR_pread_nocancel, fd, (UWord)buf, count, offset);
695    return res;
696 #  elif defined(VGP_x86_darwin)
697    vg_assert(sizeof(OffT) == 8);
698    res = VG_(do_syscall5)(__NR_pread_nocancel, fd, (UWord)buf, count,
699                           offset & 0xffffffff, offset >> 32);
700    return res;
701 #  else
702 #    error "Unknown platform"
703 #  endif
704 }
705 
706 /* Return the name of a directory for temporary files. */
VG_(tmpdir)707 const HChar *VG_(tmpdir)(void)
708 {
709    const HChar *tmpdir;
710 
711    tmpdir = VG_(getenv)("TMPDIR");
712    if (tmpdir == NULL || *tmpdir == '\0') tmpdir = VG_TMPDIR;
713    if (tmpdir == NULL || *tmpdir == '\0') tmpdir = "/tmp";    /* fallback */
714 
715    return tmpdir;
716 }
717 
718 static const HChar *mkstemp_format = "%s/valgrind_%s_%08x";
719 
VG_(mkstemp_fullname_bufsz)720 SizeT VG_(mkstemp_fullname_bufsz) ( SizeT part_of_name_len )
721 {
722    return VG_(strlen)(mkstemp_format)
723       + VG_(strlen)(VG_(tmpdir)()) - 2 // %s tmpdir
724       + part_of_name_len - 2           // %s part_of_name
725       + 8 - 4                          // %08x
726       + 1;                             // trailing 0
727 }
728 
729 
730 /* Create and open (-rw------) a tmp file name incorporating said arg.
731    Returns -1 on failure, else the fd of the file.  If fullname is
732    non-NULL, the file's name is written into it.  The number of bytes
733    written is equal to VG_(mkstemp_fullname_bufsz)(part_of_name). */
734 
VG_(mkstemp)735 Int VG_(mkstemp) ( HChar* part_of_name, /*OUT*/HChar* fullname )
736 {
737    HChar  buf[VG_(mkstemp_fullname_bufsz)(VG_(strlen)(part_of_name))];
738    Int    n, tries, fd;
739    UInt   seed;
740    SysRes sres;
741    const HChar *tmpdir;
742 
743    vg_assert(part_of_name);
744    n = VG_(strlen)(part_of_name);
745    vg_assert(n > 0 && n < 100);
746 
747    seed = (VG_(getpid)() << 9) ^ VG_(getppid)();
748 
749    /* Determine sensible location for temporary files */
750    tmpdir = VG_(tmpdir)();
751 
752    tries = 0;
753    while (True) {
754       if (tries++ > 10)
755          return -1;
756       VG_(sprintf)( buf, "%s/valgrind_%s_%08x",
757                     tmpdir, part_of_name, VG_(random)( &seed ));
758       if (0)
759          VG_(printf)("VG_(mkstemp): trying: %s\n", buf);
760 
761       sres = VG_(open)(buf,
762                        VKI_O_CREAT|VKI_O_RDWR|VKI_O_EXCL|VKI_O_TRUNC,
763                        VKI_S_IRUSR|VKI_S_IWUSR);
764       if (sr_isError(sres)) {
765          VG_(umsg)("VG_(mkstemp): failed to create temp file: %s\n", buf);
766          continue;
767       }
768       /* VG_(safe_fd) doesn't return if it fails. */
769       fd = VG_(safe_fd)( sr_Res(sres) );
770       if (fullname)
771          VG_(strcpy)( fullname, buf );
772       return fd;
773    }
774    /* NOTREACHED */
775 }
776 
777 
778 /* ---------------------------------------------------------------------
779    Socket-related stuff.
780    ------------------------------------------------------------------ */
781 
782 static
783 Int parse_inet_addr_and_port ( const HChar* str, UInt* ip_addr, UShort* port );
784 
785 static
786 Int my_connect ( Int sockfd, struct vki_sockaddr_in* serv_addr, Int addrlen );
787 
VG_(htonl)788 UInt VG_(htonl) ( UInt x )
789 {
790 #  if defined(VG_BIGENDIAN)
791    return x;
792 #  else
793    return
794       (((x >> 24) & 0xFF) << 0) | (((x >> 16) & 0xFF) << 8)
795       | (((x >> 8) & 0xFF) << 16) | (((x >> 0) & 0xFF) << 24);
796 #  endif
797 }
798 
VG_(ntohl)799 UInt VG_(ntohl) ( UInt x )
800 {
801 #  if defined(VG_BIGENDIAN)
802    return x;
803 #  else
804    return
805       (((x >> 24) & 0xFF) << 0) | (((x >> 16) & 0xFF) << 8)
806       | (((x >> 8) & 0xFF) << 16) | (((x >> 0) & 0xFF) << 24);
807 #  endif
808 }
809 
VG_(htons)810 UShort VG_(htons) ( UShort x )
811 {
812 #  if defined(VG_BIGENDIAN)
813    return x;
814 #  else
815    return
816       (((x >> 8) & 0xFF) << 0) | (((x >> 0) & 0xFF) << 8);
817 #  endif
818 }
819 
VG_(ntohs)820 UShort VG_(ntohs) ( UShort x )
821 {
822 #  if defined(VG_BIGENDIAN)
823    return x;
824 #  else
825    return
826       (((x >> 8) & 0xFF) << 0) | (((x >> 0) & 0xFF) << 8);
827 #  endif
828 }
829 
830 
831 /* The main function.
832 
833    Supplied string contains either an ip address "192.168.0.1" or
834    an ip address and port pair, "192.168.0.1:1500".  Parse these,
835    and return:
836      -1 if there is a parse error
837      -2 if no parse error, but specified host:port cannot be opened
838      the relevant file (socket) descriptor, otherwise.
839  is used.
840 */
VG_(connect_via_socket)841 Int VG_(connect_via_socket)( const HChar* str )
842 {
843 #  if defined(VGO_linux) || defined(VGO_darwin)
844    Int sd, res;
845    struct vki_sockaddr_in servAddr;
846    UInt   ip   = 0;
847    UShort port = VG_CLO_DEFAULT_LOGPORT;
848    Bool   ok   = parse_inet_addr_and_port(str, &ip, &port);
849    if (!ok)
850       return -1;
851 
852    //if (0)
853    //   VG_(printf)("ip = %d.%d.%d.%d, port %d\n",
854    //               (ip >> 24) & 0xFF, (ip >> 16) & 0xFF,
855    //               (ip >> 8) & 0xFF, ip & 0xFF,
856    //               (UInt)port );
857 
858    servAddr.sin_family = VKI_AF_INET;
859    servAddr.sin_addr.s_addr = VG_(htonl)(ip);
860    servAddr.sin_port = VG_(htons)(port);
861 
862    /* create socket */
863    sd = VG_(socket)(VKI_AF_INET, VKI_SOCK_STREAM, 0 /* IPPROTO_IP ? */);
864    if (sd < 0) {
865       /* this shouldn't happen ... nevertheless */
866       return -2;
867    }
868 
869    /* connect to server */
870    res = my_connect(sd, &servAddr, sizeof(servAddr));
871    if (res < 0) {
872       /* connection failed */
873       return -2;
874    }
875 
876    return sd;
877 
878 #  else
879 #    error "Unknown OS"
880 #  endif
881 }
882 
883 
884 /* Let d = one or more digits.  Accept either:
885    d.d.d.d  or  d.d.d.d:d
886 */
parse_inet_addr_and_port(const HChar * str,UInt * ip_addr,UShort * port)887 static Int parse_inet_addr_and_port ( const HChar* str, UInt* ip_addr, UShort* port )
888 {
889 #  define GET_CH ((*str) ? (*str++) : 0)
890    UInt ipa, i, j, c, any;
891    ipa = 0;
892    for (i = 0; i < 4; i++) {
893       j = 0;
894       any = 0;
895       while (1) {
896          c = GET_CH;
897          if (c < '0' || c > '9') break;
898          j = 10 * j + (int)(c - '0');
899          any = 1;
900       }
901       if (any == 0 || j > 255) goto syntaxerr;
902       ipa = (ipa << 8) + j;
903       if (i <= 2 && c != '.') goto syntaxerr;
904    }
905    if (c == 0 || c == ':')
906       *ip_addr = ipa;
907    if (c == 0) goto ok;
908    if (c != ':') goto syntaxerr;
909    j = 0;
910    any = 0;
911    while (1) {
912       c = GET_CH;
913       if (c < '0' || c > '9') break;
914       j = j * 10 + (int)(c - '0');
915       any = 1;
916       if (j > 65535) goto syntaxerr;
917    }
918    if (any == 0 || c != 0) goto syntaxerr;
919    if (j < 1024) goto syntaxerr;
920    *port = (UShort)j;
921  ok:
922    return 1;
923  syntaxerr:
924    return 0;
925 #  undef GET_CH
926 }
927 
928 // GrP fixme safe_fd?
VG_(socket)929 Int VG_(socket) ( Int domain, Int type, Int protocol )
930 {
931 #  if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
932       || defined(VGP_ppc64_linux) || defined(VGP_s390x_linux)
933    SysRes res;
934    UWord  args[3];
935    args[0] = domain;
936    args[1] = type;
937    args[2] = protocol;
938    res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_SOCKET, (UWord)&args);
939    return sr_isError(res) ? -1 : sr_Res(res);
940 
941 #  elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \
942         || defined(VGP_mips32_linux) || defined(VGP_mips64_linux) \
943         || defined(VGP_arm64_linux)
944    SysRes res;
945    res = VG_(do_syscall3)(__NR_socket, domain, type, protocol );
946    return sr_isError(res) ? -1 : sr_Res(res);
947 
948 #  elif defined(VGO_darwin)
949    SysRes res;
950    res = VG_(do_syscall3)(__NR_socket, domain, type, protocol);
951    if (!sr_isError(res)) {
952        // Set SO_NOSIGPIPE so write() returns EPIPE instead of raising SIGPIPE
953        Int optval = 1;
954        SysRes res2;
955        res2 = VG_(do_syscall5)(__NR_setsockopt, sr_Res(res), VKI_SOL_SOCKET,
956                                VKI_SO_NOSIGPIPE, (UWord)&optval,
957                                sizeof(optval));
958        // ignore setsockopt() error
959    }
960    return sr_isError(res) ? -1 : sr_Res(res);
961 
962 #  else
963 #    error "Unknown arch"
964 #  endif
965 }
966 
967 
968 static
my_connect(Int sockfd,struct vki_sockaddr_in * serv_addr,Int addrlen)969 Int my_connect ( Int sockfd, struct vki_sockaddr_in* serv_addr, Int addrlen )
970 {
971 #  if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
972       || defined(VGP_ppc64_linux) || defined(VGP_s390x_linux)
973    SysRes res;
974    UWord  args[3];
975    args[0] = sockfd;
976    args[1] = (UWord)serv_addr;
977    args[2] = addrlen;
978    res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_CONNECT, (UWord)&args);
979    return sr_isError(res) ? -1 : sr_Res(res);
980 
981 #  elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \
982         || defined(VGP_mips32_linux) || defined(VGP_mips64_linux) \
983         || defined(VGP_arm64_linux)
984    SysRes res;
985    res = VG_(do_syscall3)(__NR_connect, sockfd, (UWord)serv_addr, addrlen);
986    return sr_isError(res) ? -1 : sr_Res(res);
987 
988 #  elif defined(VGO_darwin)
989    SysRes res;
990    res = VG_(do_syscall3)(__NR_connect_nocancel,
991                           sockfd, (UWord)serv_addr, addrlen);
992    return sr_isError(res) ? -1 : sr_Res(res);
993 
994 #  else
995 #    error "Unknown arch"
996 #  endif
997 }
998 
VG_(write_socket)999 Int VG_(write_socket)( Int sd, const void *msg, Int count )
1000 {
1001    /* This is actually send(). */
1002 
1003    /* For Linux, VKI_MSG_NOSIGNAL is a request not to send SIGPIPE on
1004       errors on stream oriented sockets when the other end breaks the
1005       connection. The EPIPE error is still returned.
1006 
1007       For Darwin, VG_(socket)() sets SO_NOSIGPIPE to get EPIPE instead of
1008       SIGPIPE */
1009 
1010 #  if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
1011       || defined(VGP_ppc64_linux) || defined(VGP_s390x_linux)
1012    SysRes res;
1013    UWord  args[4];
1014    args[0] = sd;
1015    args[1] = (UWord)msg;
1016    args[2] = count;
1017    args[3] = VKI_MSG_NOSIGNAL;
1018    res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_SEND, (UWord)&args);
1019    return sr_isError(res) ? -1 : sr_Res(res);
1020 
1021 #  elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \
1022         || defined(VGP_mips32_linux) || defined(VGP_mips64_linux) \
1023         || defined(VGP_arm64_linux)
1024    SysRes res;
1025    res = VG_(do_syscall6)(__NR_sendto, sd, (UWord)msg,
1026                                        count, VKI_MSG_NOSIGNAL, 0,0);
1027    return sr_isError(res) ? -1 : sr_Res(res);
1028 
1029 #  elif defined(VGP_x86_darwin) || defined(VGP_amd64_darwin)
1030    SysRes res;
1031    res = VG_(do_syscall3)(__NR_write_nocancel, sd, (UWord)msg, count);
1032    return sr_isError(res) ? -1 : sr_Res(res);
1033 
1034 #  else
1035 #    error "Unknown platform"
1036 #  endif
1037 }
1038 
VG_(getsockname)1039 Int VG_(getsockname) ( Int sd, struct vki_sockaddr *name, Int *namelen)
1040 {
1041 #  if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
1042       || defined(VGP_ppc64_linux) || defined(VGP_s390x_linux) \
1043       || defined(VGP_mips32_linux)
1044    SysRes res;
1045    UWord  args[3];
1046    args[0] = sd;
1047    args[1] = (UWord)name;
1048    args[2] = (UWord)namelen;
1049    res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_GETSOCKNAME, (UWord)&args);
1050    return sr_isError(res) ? -1 : sr_Res(res);
1051 
1052 #  elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \
1053         || defined(VGP_mips64_linux) || defined(VGP_arm64_linux)
1054    SysRes res;
1055    res = VG_(do_syscall3)( __NR_getsockname,
1056                            (UWord)sd, (UWord)name, (UWord)namelen );
1057    return sr_isError(res) ? -1 : sr_Res(res);
1058 
1059 #  elif defined(VGO_darwin)
1060    SysRes res;
1061    res = VG_(do_syscall3)( __NR_getsockname,
1062                            (UWord)sd, (UWord)name, (UWord)namelen );
1063    return sr_isError(res) ? -1 : sr_Res(res);
1064 
1065 #  else
1066 #    error "Unknown platform"
1067 #  endif
1068 }
1069 
VG_(getpeername)1070 Int VG_(getpeername) ( Int sd, struct vki_sockaddr *name, Int *namelen)
1071 {
1072 #  if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
1073       || defined(VGP_ppc64_linux) || defined(VGP_s390x_linux) \
1074       || defined(VGP_mips32_linux)
1075    SysRes res;
1076    UWord  args[3];
1077    args[0] = sd;
1078    args[1] = (UWord)name;
1079    args[2] = (UWord)namelen;
1080    res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_GETPEERNAME, (UWord)&args);
1081    return sr_isError(res) ? -1 : sr_Res(res);
1082 
1083 #  elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \
1084         || defined(VGP_mips64_linux) || defined(VGP_arm64_linux)
1085    SysRes res;
1086    res = VG_(do_syscall3)( __NR_getpeername,
1087                            (UWord)sd, (UWord)name, (UWord)namelen );
1088    return sr_isError(res) ? -1 : sr_Res(res);
1089 
1090 #  elif defined(VGO_darwin)
1091    SysRes res;
1092    res = VG_(do_syscall3)( __NR_getpeername,
1093                            (UWord)sd, (UWord)name, (UWord)namelen );
1094    return sr_isError(res) ? -1 : sr_Res(res);
1095 
1096 #  else
1097 #    error "Unknown platform"
1098 #  endif
1099 }
1100 
VG_(getsockopt)1101 Int VG_(getsockopt) ( Int sd, Int level, Int optname, void *optval,
1102                       Int *optlen)
1103 {
1104 #  if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
1105       || defined(VGP_ppc64_linux) || defined(VGP_s390x_linux)
1106    SysRes res;
1107    UWord  args[5];
1108    args[0] = sd;
1109    args[1] = level;
1110    args[2] = optname;
1111    args[3] = (UWord)optval;
1112    args[4] = (UWord)optlen;
1113    res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_GETSOCKOPT, (UWord)&args);
1114    return sr_isError(res) ? -1 : sr_Res(res);
1115 
1116 #  elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \
1117         || defined(VGP_mips32_linux) || defined(VGP_mips64_linux) \
1118         || defined(VGP_arm64_linux)
1119    SysRes res;
1120    res = VG_(do_syscall5)( __NR_getsockopt,
1121                            (UWord)sd, (UWord)level, (UWord)optname,
1122                            (UWord)optval, (UWord)optlen );
1123    return sr_isError(res) ? -1 : sr_Res(res);
1124 
1125 #  elif defined(VGO_darwin)
1126    SysRes res;
1127    res = VG_(do_syscall5)( __NR_getsockopt,
1128                            (UWord)sd, (UWord)level, (UWord)optname,
1129                            (UWord)optval, (UWord)optlen );
1130    return sr_isError(res) ? -1 : sr_Res(res);
1131 
1132 #  else
1133 #    error "Unknown platform"
1134 #  endif
1135 }
1136 
1137 
VG_(setsockopt)1138 Int VG_(setsockopt) ( Int sd, Int level, Int optname, void *optval,
1139                       Int optlen)
1140 {
1141 #  if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
1142       || defined(VGP_ppc64_linux) || defined(VGP_s390x_linux)
1143    SysRes res;
1144    UWord  args[5];
1145    args[0] = sd;
1146    args[1] = level;
1147    args[2] = optname;
1148    args[3] = (UWord)optval;
1149    args[4] = (UWord)optlen;
1150    res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_SETSOCKOPT, (UWord)&args);
1151    return sr_isError(res) ? -1 : sr_Res(res);
1152 
1153 #  elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \
1154         || defined(VGP_mips32_linux) || defined(VGP_mips64_linux) \
1155         || defined(VGP_arm64_linux)
1156    SysRes res;
1157    res = VG_(do_syscall5)( __NR_setsockopt,
1158                            (UWord)sd, (UWord)level, (UWord)optname,
1159                            (UWord)optval, (UWord)optlen );
1160    return sr_isError(res) ? -1 : sr_Res(res);
1161 
1162 #  elif defined(VGO_darwin)
1163    SysRes res;
1164    res = VG_(do_syscall5)( __NR_setsockopt,
1165                            (UWord)sd, (UWord)level, (UWord)optname,
1166                            (UWord)optval, (UWord)optlen );
1167    return sr_isError(res) ? -1 : sr_Res(res);
1168 
1169 #  else
1170 #    error "Unknown platform"
1171 #  endif
1172 }
1173 
1174 
VG_(basename)1175 const HChar *VG_(basename)(const HChar *path)
1176 {
1177    static HChar buf[VKI_PATH_MAX];
1178 
1179    const HChar *p, *end;
1180 
1181    if (path == NULL  ||
1182        0 == VG_(strcmp)(path, ""))
1183    {
1184       return ".";
1185    }
1186 
1187    p = path + VG_(strlen)(path);
1188    while (p > path  &&  *p == '/') {
1189       // skip all trailing '/'
1190       p--;
1191    }
1192 
1193    if (p == path  &&  *p == '/') return "/"; // all slashes
1194 
1195    end = p;
1196 
1197    while (p > path  &&  *p != '/') {
1198       // now skip non '/'
1199       p--;
1200    }
1201 
1202    if (*p == '/') p++;
1203 
1204    VG_(strncpy)(buf, p, end-p+1);
1205    buf[end-p+1] = '\0';
1206 
1207    return buf;
1208 }
1209 
1210 
VG_(dirname)1211 const HChar *VG_(dirname)(const HChar *path)
1212 {
1213    static HChar buf[VKI_PATH_MAX];
1214 
1215    const HChar *p;
1216 
1217    if (path == NULL  ||
1218        0 == VG_(strcmp)(path, "")  ||
1219        0 == VG_(strcmp)(path, "/"))
1220    {
1221       return ".";
1222    }
1223 
1224    p = path + VG_(strlen)(path);
1225    while (p > path  &&  *p == '/') {
1226       // skip all trailing '/'
1227       p--;
1228    }
1229 
1230    while (p > path  &&  *p != '/') {
1231       // now skip non '/'
1232       p--;
1233    }
1234 
1235    if (p == path) {
1236       if (*p == '/') return "/"; // all slashes
1237       else return "."; // no slashes
1238    }
1239 
1240    while (p > path  &&  *p == '/') {
1241       // skip '/' again
1242       p--;
1243    }
1244 
1245    VG_(strncpy)(buf, path, p-path+1);
1246    buf[p-path+1] = '\0';
1247 
1248    return buf;
1249 }
1250 
1251 
1252 /*--------------------------------------------------------------------*/
1253 /*--- end                                                          ---*/
1254 /*--------------------------------------------------------------------*/
1255