aboutsummaryrefslogtreecommitdiff
path: root/src/os/fs.c
blob: 3529ab4f461dd09c668edb21c7dd8b61ac2cacf1 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/* vi:set ts=8 sts=4 sw=4:
 *
 * VIM - Vi IMproved	by Bram Moolenaar
 *
 * Do ":help uganda"  in Vim to read copying and usage conditions.
 * Do ":help credits" in Vim to see a list of people who contributed.
 * See README.txt for an overview of the Vim source code.
 */

/*
 * fs.c -- filesystem access
 */

#include <uv.h>

#include "os.h"
#include "../message.h"

int mch_chdir(char *path) {
  if (p_verbose >= 5) {
    verbose_enter();
    smsg((char_u *)"chdir(%s)", path);
    verbose_leave();
  }
  return uv_chdir(path);
}

/*
 * Get name of current directory into buffer 'buf' of length 'len' bytes.
 * Return OK for success, FAIL for failure.
 */
int mch_dirname(char_u *buf, int len)
{
  int errno;
  if ((errno = uv_cwd((char *)buf, len)) != 0) {
      STRCPY(buf, uv_strerror(errno));
      return FAIL;
  }
  return OK;
}

/*
 * Get absolute file name into "buf[len]".
 *
 * return FAIL for failure, OK for success
 */
int mch_FullName(
        char_u      *fname,
        char_u      *buf,
        int len,
        int force                       /* also expand when already absolute path */
        )
{
  int l;
  char_u olddir[MAXPATHL];
  char_u      *p;
  int retval = OK;



  /* expand it if forced or not an absolute path */
  if (force || !mch_isFullName(fname)) {
    /*
     * If the file name has a path, change to that directory for a moment,
     * and then do the getwd() (and get back to where we were).
     * This will get the correct path name with "../" things.
     */
    if ((p = vim_strrchr(fname, '/')) != NULL) {

      /* Only change directory when we are sure we can return to where
       * we are now.  After doing "su" chdir(".") might not work. */
      if ((mch_dirname(olddir, MAXPATHL) == FAIL
         || mch_chdir((char *)olddir) != 0)) {
        p = NULL;               /* can't get current dir: don't chdir */
        retval = FAIL;
      } else   {
        /* The directory is copied into buf[], to be able to remove
         * the file name without changing it (could be a string in
         * read-only memory) */
        if (p - fname >= len)
          retval = FAIL;
        else {
          vim_strncpy(buf, fname, p - fname);
          if (mch_chdir((char *)buf))
            retval = FAIL;
          else
            fname = p + 1;
          *buf = NUL;
        }
      }
    }
    if (mch_dirname(buf, len) == FAIL) {
      retval = FAIL;
      *buf = NUL;
    }
    if (p != NULL) {
      l = mch_chdir((char *)olddir);
      if (l != 0)
        EMSG(_(e_prev_dir));
    }

    l = STRLEN(buf);
    if (l >= len - 1)
      retval = FAIL;       /* no space for trailing "/" */
    else if (l > 0 && buf[l - 1] != '/' && *fname != NUL
             && STRCMP(fname, ".") != 0)
      STRCAT(buf, "/");
  }

  /* Catch file names which are too long. */
  if (retval == FAIL || (int)(STRLEN(buf) + STRLEN(fname)) >= len)
    return FAIL;

  /* Do not append ".", "/dir/." is equal to "/dir". */
  if (STRCMP(fname, ".") != 0)
    STRCAT(buf, fname);

  return OK;
}

/*
 * Return TRUE if "fname" does not depend on the current directory.
 */
int mch_isFullName(char_u *fname)
{
  return *fname == '/' || *fname == '~';
}