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