1 /* Virtual File System: SFTP file system.
2 The internal functions: dirs
3
4 Copyright (C) 2011-2021
5 Free Software Foundation, Inc.
6
7 Written by:
8 Ilia Maslakov <il.smind@gmail.com>, 2011
9 Slava Zanko <slavazanko@gmail.com>, 2011, 2012
10
11 This file is part of the Midnight Commander.
12
13 The Midnight Commander is free software: you can redistribute it
14 and/or modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation, either version 3 of the License,
16 or (at your option) any later version.
17
18 The Midnight Commander is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU 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, see <http://www.gnu.org/licenses/>.
25 */
26
27 #include <config.h>
28
29 #include <libssh2.h>
30 #include <libssh2_sftp.h>
31
32 #include "lib/global.h"
33 #include "lib/util.h"
34
35 #include "internal.h"
36
37 /*** global variables ****************************************************************************/
38
39 /*** file scope macro definitions ****************************************************************/
40
41 /*** file scope type declarations ****************************************************************/
42
43 typedef struct
44 {
45 LIBSSH2_SFTP_HANDLE *handle;
46 sftpfs_super_t *super;
47 } sftpfs_dir_data_t;
48
49 /*** file scope variables ************************************************************************/
50
51 /*** file scope functions ************************************************************************/
52 /* --------------------------------------------------------------------------------------------- */
53
54 /* --------------------------------------------------------------------------------------------- */
55 /*** public functions ****************************************************************************/
56 /* --------------------------------------------------------------------------------------------- */
57 /**
58 * Open a directory stream corresponding to the directory name.
59 *
60 * @param vpath path to directory
61 * @param mcerror pointer to the error handler
62 * @return directory data handler if success, NULL otherwise
63 */
64
65 void *
sftpfs_opendir(const vfs_path_t * vpath,GError ** mcerror)66 sftpfs_opendir (const vfs_path_t * vpath, GError ** mcerror)
67 {
68 sftpfs_dir_data_t *sftpfs_dir;
69 struct vfs_s_super *super;
70 sftpfs_super_t *sftpfs_super;
71 const vfs_path_element_t *path_element;
72 LIBSSH2_SFTP_HANDLE *handle;
73
74 mc_return_val_if_error (mcerror, NULL);
75
76 path_element = vfs_path_get_by_index (vpath, -1);
77
78 if (vfs_s_get_path (vpath, &super, 0) == NULL)
79 return NULL;
80
81 sftpfs_super = SFTP_SUPER (super);
82
83 while (TRUE)
84 {
85 const GString *fixfname;
86 int libssh_errno;
87
88 fixfname = sftpfs_fix_filename (path_element->path);
89
90 handle =
91 libssh2_sftp_open_ex (sftpfs_super->sftp_session, fixfname->str, fixfname->len, 0, 0,
92 LIBSSH2_SFTP_OPENDIR);
93 if (handle != NULL)
94 break;
95
96 libssh_errno = libssh2_session_last_errno (sftpfs_super->session);
97 if (!sftpfs_waitsocket (sftpfs_super, libssh_errno, mcerror))
98 return NULL;
99 }
100
101 sftpfs_dir = g_new0 (sftpfs_dir_data_t, 1);
102 sftpfs_dir->handle = handle;
103 sftpfs_dir->super = sftpfs_super;
104
105 return (void *) sftpfs_dir;
106 }
107
108 /* --------------------------------------------------------------------------------------------- */
109 /**
110 * Get a pointer to a structure representing the next directory entry.
111 *
112 * @param data directory data handler
113 * @param mcerror pointer to the error handler
114 * @return information about direntry if success, NULL otherwise
115 */
116
117 struct vfs_dirent *
sftpfs_readdir(void * data,GError ** mcerror)118 sftpfs_readdir (void *data, GError ** mcerror)
119 {
120 char mem[BUF_MEDIUM];
121 LIBSSH2_SFTP_ATTRIBUTES attrs;
122 sftpfs_dir_data_t *sftpfs_dir = (sftpfs_dir_data_t *) data;
123 int rc;
124
125 mc_return_val_if_error (mcerror, NULL);
126
127 do
128 {
129 rc = libssh2_sftp_readdir (sftpfs_dir->handle, mem, sizeof (mem), &attrs);
130 if (rc >= 0)
131 break;
132
133 if (!sftpfs_waitsocket (sftpfs_dir->super, rc, mcerror))
134 return NULL;
135 }
136 while (rc == LIBSSH2_ERROR_EAGAIN);
137
138 return (rc != 0 ? vfs_dirent_init (NULL, mem, 0) : NULL); /* FIXME: inode */
139 }
140
141 /* --------------------------------------------------------------------------------------------- */
142 /**
143 * Close the directory stream.
144 *
145 * @param data directory data handler
146 * @param mcerror pointer to the error handler
147 * @return 0 if success, negative value otherwise
148 */
149
150 int
sftpfs_closedir(void * data,GError ** mcerror)151 sftpfs_closedir (void *data, GError ** mcerror)
152 {
153 int rc;
154 sftpfs_dir_data_t *sftpfs_dir = (sftpfs_dir_data_t *) data;
155
156 mc_return_val_if_error (mcerror, -1);
157
158 rc = libssh2_sftp_closedir (sftpfs_dir->handle);
159 g_free (sftpfs_dir);
160 return rc;
161 }
162
163 /* --------------------------------------------------------------------------------------------- */
164 /**
165 * Create a new directory.
166 *
167 * @param vpath path directory
168 * @param mode mode (see man 2 open)
169 * @param mcerror pointer to the error handler
170 * @return 0 if success, negative value otherwise
171 */
172
173 int
sftpfs_mkdir(const vfs_path_t * vpath,mode_t mode,GError ** mcerror)174 sftpfs_mkdir (const vfs_path_t * vpath, mode_t mode, GError ** mcerror)
175 {
176 int res;
177 struct vfs_s_super *super;
178 sftpfs_super_t *sftpfs_super;
179 const vfs_path_element_t *path_element;
180
181 mc_return_val_if_error (mcerror, -1);
182
183 path_element = vfs_path_get_by_index (vpath, -1);
184
185 if (vfs_s_get_path (vpath, &super, 0) == NULL)
186 return -1;
187
188 if (super == NULL)
189 return -1;
190
191 sftpfs_super = SFTP_SUPER (super);
192 if (sftpfs_super->sftp_session == NULL)
193 return -1;
194
195 do
196 {
197 const GString *fixfname;
198
199 fixfname = sftpfs_fix_filename (path_element->path);
200
201 res =
202 libssh2_sftp_mkdir_ex (sftpfs_super->sftp_session, fixfname->str, fixfname->len, mode);
203 if (res >= 0)
204 break;
205
206 if (!sftpfs_waitsocket (sftpfs_super, res, mcerror))
207 return -1;
208 }
209 while (res == LIBSSH2_ERROR_EAGAIN);
210
211 return res;
212 }
213
214 /* --------------------------------------------------------------------------------------------- */
215 /**
216 * Remove a directory.
217 *
218 * @param vpath path directory
219 * @param mcerror pointer to the error handler
220 * @return 0 if success, negative value otherwise
221 */
222
223 int
sftpfs_rmdir(const vfs_path_t * vpath,GError ** mcerror)224 sftpfs_rmdir (const vfs_path_t * vpath, GError ** mcerror)
225 {
226 int res;
227 struct vfs_s_super *super;
228 sftpfs_super_t *sftpfs_super;
229 const vfs_path_element_t *path_element;
230
231 mc_return_val_if_error (mcerror, -1);
232
233 path_element = vfs_path_get_by_index (vpath, -1);
234
235 if (vfs_s_get_path (vpath, &super, 0) == NULL)
236 return -1;
237
238 if (super == NULL)
239 return -1;
240
241 sftpfs_super = SFTP_SUPER (super);
242 if (sftpfs_super->sftp_session == NULL)
243 return -1;
244
245 do
246 {
247 const GString *fixfname;
248
249 fixfname = sftpfs_fix_filename (path_element->path);
250
251 res = libssh2_sftp_rmdir_ex (sftpfs_super->sftp_session, fixfname->str, fixfname->len);
252 if (res >= 0)
253 break;
254
255 if (!sftpfs_waitsocket (sftpfs_super, res, mcerror))
256 return -1;
257 }
258 while (res == LIBSSH2_ERROR_EAGAIN);
259
260 return res;
261 }
262
263 /* --------------------------------------------------------------------------------------------- */
264