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