1 /* Virtual File System: SFTP file system.
2 The internal functions: dirs
3
4 Copyright (C) 2011-2025
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 <https://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 *
66 sftpfs_opendir (const vfs_path_t *vpath, GError **mcerror)
/* ![[previous]](../icons/n_left.png)
![[next]](../icons/right.png)
![[first]](../icons/n_first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
67 {
68 sftpfs_dir_data_t *sftpfs_dir;
69 sftpfs_super_t *sftpfs_super;
70 const vfs_path_element_t *path_element;
71 LIBSSH2_SFTP_HANDLE *handle = NULL;
72 const GString *fixfname;
73
74 if (!sftpfs_op_init (&sftpfs_super, &path_element, vpath, mcerror))
75 return NULL;
76
77 fixfname = sftpfs_fix_filename (path_element->path);
78
79 while (TRUE)
80 {
81 int libssh_errno;
82
83 handle = libssh2_sftp_open_ex (sftpfs_super->sftp_session, fixfname->str, fixfname->len, 0,
84 0, LIBSSH2_SFTP_OPENDIR);
85 if (handle != NULL)
86 break;
87
88 libssh_errno = libssh2_session_last_errno (sftpfs_super->session);
89 if (!sftpfs_waitsocket (sftpfs_super, libssh_errno, mcerror))
90 return NULL;
91 }
92
93 sftpfs_dir = g_new0 (sftpfs_dir_data_t, 1);
94 sftpfs_dir->handle = handle;
95 sftpfs_dir->super = sftpfs_super;
96
97 return (void *) sftpfs_dir;
98 }
99
100 /* --------------------------------------------------------------------------------------------- */
101 /**
102 * Get a pointer to a structure representing the next directory entry.
103 *
104 * @param data directory data handler
105 * @param mcerror pointer to the error handler
106 * @return information about direntry if success, NULL otherwise
107 */
108
109 struct vfs_dirent *
110 sftpfs_readdir (void *data, GError **mcerror)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
111 {
112 char mem[BUF_MEDIUM];
113 LIBSSH2_SFTP_ATTRIBUTES attrs;
114 sftpfs_dir_data_t *sftpfs_dir = (sftpfs_dir_data_t *) data;
115 int rc;
116
117 mc_return_val_if_error (mcerror, NULL);
118
119 do
120 {
121 rc = libssh2_sftp_readdir (sftpfs_dir->handle, mem, sizeof (mem), &attrs);
122 if (rc >= 0)
123 break;
124
125 if (!sftpfs_waitsocket (sftpfs_dir->super, rc, mcerror))
126 return NULL;
127 }
128 while (rc == LIBSSH2_ERROR_EAGAIN);
129
130 return (rc != 0 ? vfs_dirent_init (NULL, mem, 0) : NULL); // FIXME: inode
131 }
132
133 /* --------------------------------------------------------------------------------------------- */
134 /**
135 * Close the directory stream.
136 *
137 * @param data directory data handler
138 * @param mcerror pointer to the error handler
139 * @return 0 if success, negative value otherwise
140 */
141
142 int
143 sftpfs_closedir (void *data, GError **mcerror)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
144 {
145 int rc;
146 sftpfs_dir_data_t *sftpfs_dir = (sftpfs_dir_data_t *) data;
147
148 mc_return_val_if_error (mcerror, -1);
149
150 rc = libssh2_sftp_closedir (sftpfs_dir->handle);
151 g_free (sftpfs_dir);
152 return rc;
153 }
154
155 /* --------------------------------------------------------------------------------------------- */
156 /**
157 * Create a new directory.
158 *
159 * @param vpath path directory
160 * @param mode mode (see man 2 open)
161 * @param mcerror pointer to the error handler
162 * @return 0 if success, negative value otherwise
163 */
164
165 int
166 sftpfs_mkdir (const vfs_path_t *vpath, mode_t mode, GError **mcerror)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
167 {
168 int res;
169 sftpfs_super_t *sftpfs_super;
170 const vfs_path_element_t *path_element;
171 const GString *fixfname;
172
173 if (!sftpfs_op_init (&sftpfs_super, &path_element, vpath, mcerror))
174 return -1;
175
176 fixfname = sftpfs_fix_filename (path_element->path);
177
178 do
179 {
180 res =
181 libssh2_sftp_mkdir_ex (sftpfs_super->sftp_session, fixfname->str, fixfname->len, mode);
182 if (res >= 0)
183 break;
184
185 if (!sftpfs_waitsocket (sftpfs_super, res, mcerror))
186 return -1;
187 }
188 while (res == LIBSSH2_ERROR_EAGAIN);
189
190 return res;
191 }
192
193 /* --------------------------------------------------------------------------------------------- */
194 /**
195 * Remove a directory.
196 *
197 * @param vpath path directory
198 * @param mcerror pointer to the error handler
199 * @return 0 if success, negative value otherwise
200 */
201
202 int
203 sftpfs_rmdir (const vfs_path_t *vpath, GError **mcerror)
/* ![[previous]](../icons/left.png)
![[next]](../icons/n_right.png)
![[first]](../icons/first.png)
![[last]](../icons/n_last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
204 {
205 int res;
206 sftpfs_super_t *sftpfs_super;
207 const vfs_path_element_t *path_element;
208 const GString *fixfname;
209
210 if (!sftpfs_op_init (&sftpfs_super, &path_element, vpath, mcerror))
211 return -1;
212
213 fixfname = sftpfs_fix_filename (path_element->path);
214
215 do
216 {
217 res = libssh2_sftp_rmdir_ex (sftpfs_super->sftp_session, fixfname->str, fixfname->len);
218 if (res >= 0)
219 break;
220
221 if (!sftpfs_waitsocket (sftpfs_super, res, mcerror))
222 return -1;
223 }
224 while (res == LIBSSH2_ERROR_EAGAIN);
225
226 return res;
227 }
228
229 /* --------------------------------------------------------------------------------------------- */