3 * Copyright (C) 2002 Florin Malita <mali@go.ro>
5 * This file is part of LUFS, a free userspace filesystem implementation.
6 * See http://lufs.sourceforge.net/ for updates.
8 * LUFS is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * LUFS is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #include <sys/types.h>
29 #include <lufs/proto.h>
37 #include "ftpsys_unix.h"
38 #include "ftpsys_netware.h"
39 #include "ftpsys_windows.h"
44 ftpfs_init(struct list_head *cfg, struct dir_cache *cache, struct credentials *cred, void **global_ctx){
46 if(!lu_opt_getchar(cfg, "MOUNT", "host")){
47 ERROR("you must specify a host!");
51 return (void*)new FTPFS(cfg, cache, cred);
55 ftpfs_free(void *ctx){
56 FTPFS *p = (FTPFS*)ctx;
62 ftpfs_mount(void *ctx){
63 return ((FTPFS*)ctx)->do_mount();
67 ftpfs_umount(void *ctx){
68 // return ((FTPFS*)ctx)->do_umount();
72 ftpfs_readdir(void *ctx, char *dir_name, struct directory *dir){
73 return ((FTPFS*)ctx)->do_readdir(dir_name, dir);
77 ftpfs_stat(void *ctx, char *name, struct lufs_fattr *fattr){
78 return ((FTPFS*)ctx)->do_stat(name, fattr);
82 ftpfs_mkdir(void *ctx, char *dir, int mode){
83 return ((FTPFS*)ctx)->do_mkdir(dir, mode);
87 ftpfs_rmdir(void *ctx, char *dir){
88 return ((FTPFS*)ctx)->do_rmdir(dir);
92 ftpfs_create(void *ctx, char *file, int mode){
93 return ((FTPFS*)ctx)->do_create(file, mode);
97 ftpfs_unlink(void *ctx, char *file){
98 return ((FTPFS*)ctx)->do_unlink(file);
102 ftpfs_rename(void *ctx, char *old_name, char *new_name){
103 return ((FTPFS*)ctx)->do_rename(old_name, new_name);
107 ftpfs_open(void *ctx, char *file, unsigned mode){
108 return ((FTPFS*)ctx)->do_open(file, mode);
112 ftpfs_release(void *ctx, char *file){
113 return ((FTPFS*)ctx)->do_release(file);
117 ftpfs_read(void *ctx, char *file, long long offset, unsigned long count, char *buf){
118 return ((FTPFS*)ctx)->do_read(file, offset, count, buf);
122 ftpfs_write(void *ctx, char *file, long long offset, unsigned long count, char *buf){
123 return ((FTPFS*)ctx)->do_write(file, offset, count, buf);
127 ftpfs_readlink(void *ctx, char *link, char *buf, int buflen){
128 return ((FTPFS*)ctx)->do_readlink(link, buf, buflen);
132 ftpfs_link(void *ctx, char *target, char *link){
137 ftpfs_symlink(void *ctx, char *target, char *link){
142 ftpfs_setattr(void *ctx, char *file, struct lufs_fattr *fattr){
143 return ((FTPFS*)ctx)->do_setattr(file, fattr);
151 FTPFS::FTPFS(struct list_head *cf, struct dir_cache *cache, struct credentials *cred){
152 const char *c, *user, *pass;
156 TRACE("in constructor");
163 if((c = lu_opt_getchar(cfg, "FTPFS", "RWTimeout"))){
164 rw_timeout = atoi(c);
165 TRACE("RWTimeout set to "<<rw_timeout);
171 if((c = lu_opt_getchar(cfg, "FTPFS", "DataConnectionMode"))){
172 TRACE("DataConnectionMode set to "<<c);
173 if(!strcmp(c, "Active")){
178 if(lu_opt_getchar(cfg, "MOUNT", "ftpactive")){
179 TRACE("DataConnectionMode set to active");
183 if(lu_opt_getchar(cfg, "MOUNT", "ftppassive")){
184 TRACE("DataConnectionMode set to passive");
188 if(lu_opt_getint(cfg, "MOUNT", "port", &port, 10) < 0)
191 if(!(user = lu_opt_getchar(cfg, "MOUNT", "username")))
194 if(!(pass = lu_opt_getchar(cfg, "MOUNT", "password")))
195 pass = "user@sourceforge.net";
197 conn = new FTPConnection(active, (char*)lu_opt_getchar(cfg, "MOUNT", "host"), port, (char*)user, (char*)pass);
203 TRACE("in destructor");
215 res = conn->connect();
217 /* ftpsys initialization */
218 if(!strcmp(conn->system, "NETWARE"))
219 ftpsys = new ftpsys_netware();
220 else if(!strcmp(conn->system, "Windows_NT"))
221 ftpsys = new ftpsys_windows();
223 ftpsys = new ftpsys_unix();
225 TRACE("list command: "<<ftpsys->CMD_LIST);
229 return (res < 0) ? 0 : 1;
240 FTPFS::do_readdir(char *dir, struct directory *d){
242 struct lufs_fattr fattr;
245 char *file = new char[FTP_MAXFILE];
246 char *link = new char[FTP_MAXFILE];
247 char *buf = new char[FTP_MAXLINE];
249 if((res = conn->execute_retry(string("CWD ") + dir, 250, 1)) < 0){
254 if((res = conn->execute_open(string(ftpsys->CMD_LIST), string("A"), 0)) < 0){
255 WARN("execute_open failed!");
259 if((res = lu_check_to(conn->dsock, 0, rw_timeout))){
264 while(fgets(buf, FTP_MAXLINE, conn->dfd)){
265 if(ftpsys->parse_line(buf, file, &fattr, link, cred) >= 0){
266 lu_cache_add2dir(d, file, link, &fattr);
269 if(ferror(conn->dfd)){
285 FTPFS::do_stat(char *file, struct lufs_fattr *fattr){
286 string link, s(file);
290 TRACE("file: "<<file);
292 if((i = s.find_last_of('/')) == string::npos){
293 WARN("couldn't isolate dir in "<<file<<"!");
297 string dir = (i == 0) ? string("/") : s.substr(0, i);
298 string f = s.substr(i + 1, s.length() - i - 1);
300 if(!(ddir = lu_cache_mkdir((char*)dir.c_str())))
303 if(do_readdir((char*)dir.c_str(), (struct directory*)ddir) < 0){
304 WARN("do_readdir failed!");
305 lu_cache_killdir((struct directory*)ddir);
309 lu_cache_add_dir(cache, (struct directory*)ddir);
311 if(lu_cache_lookup(cache, (char*)dir.c_str(), (char*)f.c_str(), fattr, NULL, 0) < 0)
318 FTPFS::do_readlink(char *lnk, char *buf, int buflen){
321 struct lufs_fattr fattr;
326 if((i = s.find_last_of('/')) == string::npos){
327 WARN("couldn't isolate dir in "<<lnk<<"!");
331 string dir = (i == 0) ? string("/") : s.substr(0, i);
332 string f = s.substr(i + 1, s.length() - i - 1);
334 if(!(ddir = lu_cache_mkdir((char*)dir.c_str())))
337 if(do_readdir((char*)dir.c_str(), (struct directory*)ddir) < 0){
338 WARN("do_readdir failed!");
339 lu_cache_killdir((struct directory*)ddir);
343 lu_cache_add_dir(cache, (struct directory*)ddir);
345 if(lu_cache_lookup(cache, (char*)dir.c_str(), (char*)f.c_str(), &fattr, buf, buflen) < 0){
346 WARN("lookup still failing... why!?!?!?");
354 FTPFS::do_open(char *file, unsigned mode){
361 FTPFS::do_release(char *file){
368 FTPFS::do_read(char *file, long long offset, unsigned long count, char *b){
369 int res = 0, tries = 0;
372 TRACE("read "<<file<<", "<<offset<<", "<<count);
374 if(tries++ > FTP_MAXTRIES){
375 WARN("too many failures!");
382 if((res = conn->execute_open(string("RETR ") + file, string("I"), offset)) < 0){
383 WARN("couldn't open data connection!");
387 if((res = lu_check_to(conn->dsock, 0, rw_timeout))){
392 if((res = fread(b, 1, count, conn->dfd)) < (int)count){
393 TRACE("short read: "<<res);
394 if(ferror(conn->dfd)){
400 conn->last_off += res;
406 FTPFS::do_mkdir(char *dir, int mode){
411 if((res = conn->execute_retry(string("MKD ") + dir, 257, 1)) < 0){
412 WARN("MKDIR failed!");
421 FTPFS::do_rmdir(char *dir){
426 if((res = conn->execute_retry(string("RMD ") + dir, 0, 1)) < 0){
427 WARN("execute failed!");
431 /* Ugly WarFTP hack */
432 if((conn->get_response() / 100) != 2){
433 WARN("RMDIR failed!");
441 FTPFS::do_unlink(char *file){
446 if((res = conn->execute_retry(string("DELE ") + file, 250, 1)) < 0){
447 WARN("DELE failed!");
455 FTPFS::do_create(char *file, int mode){
460 if((res = conn->execute_open(string("STOR ") + file, string("I"), 0)) < 0){
461 WARN("couldn't create file!");
471 FTPFS::do_rename(char *old, char *nnew){
476 if((res = conn->execute_retry(string("RNFR ") + old, 350, 1)) < 0){
477 WARN("RNFR failed!");
482 if((res = conn->execute_retry(string("RNTO ") + nnew, 250, 1)) < 0){
483 WARN("RNTO failed!");
491 FTPFS::do_write(char *file, long long offset, unsigned long count, char *b){
492 int res = 0, tries = 0;
497 if(tries++ > FTP_MAXTRIES){
498 WARN("too many failures!");
505 if((res = conn->execute_open(string("STOR ") + file, string("I"), offset)) < 0){
506 WARN("couldn't open data connection!");
510 if((res = lu_check_to(0, conn->dsock, rw_timeout))){
515 if((res = fwrite(b, 1, count, conn->dfd)) < (int)count){
516 TRACE("short write: "<<res);
517 if(ferror(conn->dfd)){
523 conn->last_off += res;
529 FTPFS::do_setattr(char *file, struct lufs_fattr *fattr){
533 TRACE("setattr "<<file);
535 if(snprintf(buf, 10, "%lo", fattr->f_mode & 0777) >= 10)
538 string cmd = string ("SITE CHMOD ") + buf + string(" ") + file;
542 if((res = conn->execute_retry(cmd, 200, 1)) < 0){
543 WARN("SITE CHMOD failed!");