1 #include "../filezilla.h"
2 
3 #include "../directorycache.h"
4 #include "list.h"
5 
6 enum listStates
7 {
8 	list_init = 0,
9 	list_waitlock,
10 	list_list
11 };
12 
Send()13 int CStorjListOpData::Send()
14 {
15 	switch (opState) {
16 	case list_init:
17 		path_ = CServerPath::GetChanged(currentPath_, path_, subDir_);
18 		subDir_.clear();
19 		if (path_.empty()) {
20 			path_ = CServerPath(L"/");
21 		}
22 		currentPath_ = path_;
23 
24 		log(logmsg::status, _("Retrieving directory listing of \"%s\"..."), currentPath_.GetPath());
25 
26 		if (currentPath_.GetType() != ServerType::UNIX) {
27 			log(logmsg::debug_warning, L"CStorjListOpData::Send called with incompatible server type %d in path", currentPath_.GetType());
28 			return FZ_REPLY_INTERNALERROR;
29 		}
30 
31 		opState = list_waitlock;
32 		if (!opLock_) {
33 			opLock_ = controlSocket_.Lock(locking_reason::list, path_);
34 			time_before_locking_ = fz::monotonic_clock::now();
35 		}
36 		if (opLock_.waiting()) {
37 			return FZ_REPLY_WOULDBLOCK;
38 		}
39 
40 		opState = list_list;
41 		return FZ_REPLY_CONTINUE;
42 	case list_waitlock:
43 		if (!opLock_) {
44 			log(logmsg::debug_warning, L"Not holding the lock as expected");
45 			return FZ_REPLY_INTERNALERROR;
46 		}
47 
48 		{
49 			// Check if we can use already existing listing
50 			CDirectoryListing listing;
51 			bool is_outdated = false;
52 			bool found = engine_.GetDirectoryCache().Lookup(listing, currentServer_, path_, false, is_outdated);
53 			if (found && !is_outdated &&
54 				listing.m_firstListTime >= time_before_locking_)
55 			{
56 				controlSocket_.SendDirectoryListingNotification(listing.path, false);
57 				return FZ_REPLY_OK;
58 			}
59 		}
60 		opState = list_list;
61 		return FZ_REPLY_CONTINUE;
62 	case list_list:
63 		return controlSocket_.SendCommand(L"list " + controlSocket_.QuoteFilename(path_.GetPath()));
64 	}
65 
66 	log(logmsg::debug_warning, L"Unknown opState in CStorjListOpData::Send()");
67 	return FZ_REPLY_INTERNALERROR;
68 }
69 
ParseResponse()70 int CStorjListOpData::ParseResponse()
71 {
72 	if (opState == list_list) {
73 		if (controlSocket_.result_ != FZ_REPLY_OK) {
74 			return controlSocket_.result_;
75 		}
76 		CDirectoryListing listing;
77 		listing.path = path_;
78 		listing.m_firstListTime = fz::monotonic_clock::now();
79 		listing.Assign(std::move(entries_));
80 
81 		engine_.GetDirectoryCache().Store(listing, currentServer_);
82 		controlSocket_.SendDirectoryListingNotification(listing.path, false);
83 
84 		currentPath_ = path_;
85 		return FZ_REPLY_OK;
86 	}
87 
88 	log(logmsg::debug_warning, L"CStorjListOpData::ParseResponse called at improper time: %d", opState);
89 	return FZ_REPLY_INTERNALERROR;
90 }
91 
ParseEntry(std::wstring && name,std::wstring const & size,std::wstring const & created)92 int CStorjListOpData::ParseEntry(std::wstring && name, std::wstring const& size, std::wstring const& created)
93 {
94 	if (opState != list_list) {
95 		log(logmsg::debug_warning, L"CStorjListOpData::ParseEntry called at improper time: %d", opState);
96 		return FZ_REPLY_INTERNALERROR;
97 	}
98 
99 	CDirentry entry;
100 	entry.name = name;
101 	if (!path_.SegmentCount() ) {
102 		entry.flags = CDirentry::flag_dir;
103 	}
104 	else {
105 		if (!entry.name.empty() && entry.name.back() == '/') {
106 			entry.flags = CDirentry::flag_dir;
107 			entry.name.pop_back();
108 		}
109 		else {
110 			entry.flags = 0;
111 		}
112 	}
113 
114 	if (entry.is_dir()) {
115 		entry.size = -1;
116 	}
117 	else {
118 		entry.size = fz::to_integral<int64_t>(size, -1);
119 	}
120 
121 	time_t t = fz::to_integral<time_t>(created);
122 	if (t) {
123 		entry.time = fz::datetime(t, fz::datetime::seconds);
124 	}
125 
126 	if (!entry.name.empty()) {
127 		entries_.emplace_back(std::move(entry));
128 	}
129 
130 	return FZ_REPLY_WOULDBLOCK;
131 }
132