plptools
Loading...
Searching...
No Matches
rfsv16.cc
Go to the documentation of this file.
1/*
2 * This file is part of plptools.
3 *
4 * Copyright (C) 1999 Philip Proudman <philip.proudman@btinternet.com>
5 * Copyright (C) 1999 Matt J. Gumbley <matt@gumbley.demon.co.uk>
6 * Copyright (C) 1999-2002 Fritz Elfert <felfert@to.com>
7 *
8 * This program 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.
12 *
13 * This program 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.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * along with this program; if not, see <https://www.gnu.org/licenses/>.
20 *
21 */
22#include "config.h"
23
24#include "rfsv16.h"
25
26#include "bufferarray.h"
27#include "bufferstore.h"
28#include "drive.h"
29#include "plpdirent.h"
30#include "tcpsocket.h"
31
32#include <algorithm>
33#include <ios>
34#include <iostream>
35#include <fstream>
36
37#include <stdlib.h>
38#include <time.h>
39
40#include "ignore-value.h"
41
42#define RFSV16_MAXDATALEN 852 // 640
43
44using namespace std;
45
46RFSV16::RFSV16(std::unique_ptr<TCPSocket> socket) {
47 operationId_ = 0;
49 socket_ = std::move(socket);
50 reset();
51}
52
53Enum<RFSV::errs> RFSV16::fopen(uint32_t attr, const char *name, uint32_t &handle) {
55 string realName = convertSlash(name);
56
57 // Allow random access, rather than forcing the caller to ask for it
58 a.addWord((P_FRANDOM | attr) & 0xFFFF);
59 a.addStringT(realName.c_str());
60 if (!sendCommand(SIBO_FOPEN, a)) {
61 return E_PSI_FILE_DISC;
62 }
63
65 if (res == 0) {
66 handle = static_cast<long>(a.getWord(0));
67 return E_PSI_GEN_NONE;
68 }
69 return res;
70}
71
72Enum<RFSV::errs> RFSV16::mktemp(uint32_t &handle, string &tmpname) {
74
75 a.addWord(P_FUNIQUE);
76 a.addStringT("TMP");
78 return E_PSI_FILE_DISC;
79 }
80
82 if (res == E_PSI_GEN_NONE) {
83 handle = a.getWord(0);
84 tmpname = a.getString(2);
85 return res;
86 }
87 return res;
88}
89
90Enum<RFSV::errs> RFSV16::fcreatefile(uint32_t attr, const char *name, uint32_t &handle) {
91 return fopen(attr | P_FCREATE, name, handle);
92}
93
94Enum<RFSV::errs> RFSV16::freplacefile(uint32_t attr, const char *name, uint32_t &handle) {
95 return fopen(attr | P_FREPLACE, name, handle);
96}
97
98Enum<RFSV::errs> RFSV16::fopendir(const char * const name, uint32_t &handle) {
99 return fopen(P_FDIR, name, handle);
100}
101
102Enum<RFSV::errs> RFSV16::fclose(uint32_t fileHandle) {
104 a.addWord(fileHandle & 0xFFFF);
105 if (!sendCommand(SIBO_FCLOSE, a)) {
106 return E_PSI_FILE_DISC;
107 }
108 return getResponse(a);
109}
110
111Enum<RFSV::errs> RFSV16::opendir(const uint32_t attr, const char *name, RFSVDirHandle &dH) {
112 (void)attr;
113 uint32_t handle;
114 Enum<RFSV::errs> res = fopendir(name, handle);
115 dH.h = handle;
116 dH.b.init();
117 dH.name_ = name;
118 return res;
119}
120
122 return fclose(dH.h);
123}
124
127
128 if (dH.b.getLen() < 17) {
129 dH.b.init();
130 dH.b.addWord(dH.h & 0xFFFF);
131 if (!sendCommand(SIBO_FDIRREAD, dH.b)) {
132 return E_PSI_FILE_DISC;
133 }
134 res = getResponse(dH.b);
135 if (res == E_PSI_GEN_NONE) {
136 uint16_t bufferLen = dH.b.getWord(0);
137 dH.b.discardFirstBytes(2);
138 if (dH.b.getLen() != bufferLen) {
139 return E_PSI_GEN_FAIL;
140 }
141 }
142 }
143 if ((res == E_PSI_GEN_NONE) && (dH.b.getLen() > 16)) {
144 uint16_t version = dH.b.getWord(0);
145 if (version != 2) {
146 return E_PSI_GEN_FAIL;
147 }
148 e.attr = attr2std(static_cast<uint32_t>(dH.b.getWord(2)));
149 e.size = dH.b.getDWord(4);
150 e.time.setSiboTime(dH.b.getDWord(8));
151 e.dirname_ = dH.name_;
152 e.name = dH.b.getString(16);
153 e.attrstr = attr2String(e.attr);
154
155 dH.b.discardFirstBytes(17 + e.name.length());
156
157 }
158 return res;
159}
160
161Enum<RFSV::errs> RFSV16::dir(const char *name, PlpDir &files) {
163 files.clear();
165 while (res == E_PSI_GEN_NONE) {
166 PlpDirent e;
167 res = readdir(h, e);
168 if (res == E_PSI_GEN_NONE) {
169 files.push_back(e);
170 }
171 }
172 closedir(h);
173 if (res == E_PSI_FILE_EOF) {
174 res = E_PSI_GEN_NONE;
175 }
176 return res;
177}
178
179uint32_t RFSV16::opMode(uint32_t mode) {
180 uint32_t ret = 0;
181
182 ret |= ((mode & 03) == PSI_O_RDONLY) ? 0 : P_FUPDATE;
183 ret |= (mode & PSI_O_TRUNC) ? P_FREPLACE : 0;
184 ret |= (mode & PSI_O_CREAT) ? P_FCREATE : 0;
185 ret |= (mode & PSI_O_APPEND) ? P_FAPPEND : 0;
186 if ((mode & 03) == PSI_O_RDONLY) {
187 ret |= (mode & PSI_O_EXCL) ? 0 : P_FSHARE;
188 }
189 return ret;
190}
191
192Enum<RFSV::errs> RFSV16::fgetmtime(const char * const name, PsiTime &mtime) {
194 string realName = convertSlash(name);
195 a.addStringT(realName.c_str());
196 if (!sendCommand(SIBO_FINFO, a)) {
197 return E_PSI_FILE_DISC;
198 }
199
201 if (res != E_PSI_GEN_NONE) {
202 return res;
203 } else if (a.getLen() == 16) {
204 // According to Alex's docs, Psion's file times are in
205 // seconds since 13:00!!, 1.1.1970
206 mtime.setSiboTime(a.getDWord(8));
207 return res;
208 }
209 return E_PSI_GEN_FAIL;
210}
211
213 // According to Alexander's protocol doc, SIBO_SFDATE sets the modification
214 // time - and as far as I can see SIBO only keeps a modification
215 // time. So call SIBO_SFDATE here.
217 string realName = convertSlash(name);
218 // According to Alex's docs, Psion's file times are in
219 // seconds since 13:00!!, 1.1.1970
220 a.addDWord(mtime.getSiboTime());
221 a.addStringT(realName.c_str());
222 if (!sendCommand(SIBO_SFDATE, a)) {
223 return E_PSI_FILE_DISC;
224 }
225 return getResponse(a);
226}
227
228Enum<RFSV::errs> RFSV16::fgetattr(const char * const name, uint32_t &attr) {
230 string realName = convertSlash(name);
231 a.addStringT(realName.c_str());
232 if (!sendCommand(SIBO_FINFO, a)) {
233 return E_PSI_FILE_DISC;
234 }
235
237 if (res != E_PSI_GEN_NONE) {
238 return res;
239 } else if (a.getLen() == 16) {
240 attr = attr2std(static_cast<long>(a.getWord(2)));
241 return res;
242 }
243 return E_PSI_GEN_FAIL;
244}
245
246Enum<RFSV::errs> RFSV16::fgeteattr(const char *const name, PlpDirent &e) {
248 string realName = convertSlash(name);
249 a.addStringT(realName.c_str());
250 if (!sendCommand(SIBO_FINFO, a))
251 return E_PSI_FILE_DISC;
253 if (res != E_PSI_GEN_NONE)
254 return res;
255 else if (a.getLen() == 16) {
256
257 // Get the filename.
258 const char *p = strrchr(realName.c_str(), '\\');
259 if (p) {
260 p++;
261 } else {
262 p = realName.c_str();
263 }
264
265 // Uppercase the resulting filename as, while EPOC16 is case insensitive, it returns all responses as uppercase.
266 string filename = p;
267 std::transform(filename.begin(), filename.end(), filename.begin(), ::toupper);
268
269 e.name = filename;
270 e.attr = attr2std(static_cast<long>(a.getWord(2)));
271 e.size = a.getDWord(4);
272 e.time.setSiboTime(a.getDWord(8));
273 e.UID = PlpUID(0,0,0);
274 e.attrstr = string(attr2String(e.attr));
275 return res;
276 }
277 return E_PSI_GEN_FAIL;
278}
279
280Enum<RFSV::errs> RFSV16::fsetattr(const char *name, uint32_t seta, uint32_t unseta) {
281 uint32_t statusword = std2attr(seta) & (~ std2attr(unseta));
282 statusword ^= 0x0000001; // r bit is inverted
283 uint32_t bitmask = std2attr(seta) | std2attr(unseta);
285 a.addWord(statusword & 0xFFFF);
286 a.addWord(bitmask & 0xFFFF);
287 a.addStringT(name);
288 if (!sendCommand(SIBO_SFSTAT, a)) {
289 return E_PSI_FILE_DISC;
290 }
291 return getResponse(a);
292}
293
294Enum<RFSV::errs> RFSV16::dircount(const char * const name, uint32_t &count) {
297 while (res == E_PSI_GEN_NONE) {
298 PlpDirent e;
299 res = readdir(h, e);
300 if (res == E_PSI_GEN_NONE) {
301 count++;
302 }
303 }
304 closedir(h);
305 if (res == E_PSI_FILE_EOF) {
306 res = E_PSI_GEN_NONE;
307 }
308 return res;
309}
310
313 uint32_t fileHandle;
314 devbits = 0;
315
316 // The following is taken from a trace between a Series 3c and PsiWin.
317 // Hope it works! We SIBO_PARSE to find the correct node, then FOPEN
318 // (P_FDEVICE) this, SIBO_FDEVICEREAD each entry, setting the appropriate
319 // drive-letter-bit in devbits, then FCLOSE.
320
322 a.init();
323 a.addByte(0x00); // no Name 1
324 a.addByte(0x00); // no Name 2
325 a.addByte(0x00); // no Name 3
326 if (!sendCommand(SIBO_PARSE, a)) {
327 return E_PSI_FILE_DISC;
328 }
329 res = getResponse(a);
330 if (res != E_PSI_GEN_NONE) {
331 return res;
332 }
333
334 // Find the drive to FOPEN
335 char name[4] = { 'x', ':', '\\', '\0' } ;
336 a.discardFirstBytes(6); // Result, fsys, dev, path, file, file, ending, flag
337 /* This leaves R E M : : M : \ */
338 name[0] = static_cast<char>(a.getByte(5)); // the M
339 res = fopen(P_FDEVICE, name, fileHandle);
340 if (res != E_PSI_GEN_NONE) {
341 return status_;
342 }
343
344 while (1) {
345 a.init();
346 a.addWord(fileHandle & 0xFFFF);
348 return E_PSI_FILE_DISC;
349 res = getResponse(a);
350 if (res)
351 break;
352 uint16_t version = a.getWord(0);
353 if ((version < 1) || (version > 2)) {
354 cerr << "devlist: not version 1 or 2" << endl;
355 fclose(fileHandle);
356 return E_PSI_GEN_FAIL;
357 }
358 char drive = a.getByte(64);
359 if (drive >= 'A' && drive <= 'Z') {
360 int shift = (drive - 'A');
361 devbits |= static_cast<long>(1 << shift);
362 } else {
363 cerr << "devlist: non-alphabetic drive letter ("
364 << drive << ")" << endl;
365 }
366 }
367 if (res == E_PSI_FILE_EOF) {
368 res = E_PSI_GEN_NONE;
369 }
370 fclose(fileHandle);
371 return res;
372}
373
374static int sibo_dattr[] = {
375 1, // Unknown
376 2, // Floppy
377 3, // Disk
378 6, // Flash
379 5, // RAM
380 7, // ROM
381 7, // write-protected == ROM ?
382};
383
384Enum<RFSV::errs> RFSV16::devinfo(const char drive, Drive &dinfo) {
387
388 // Again, this is taken from an exchange between PsiWin and a 3c.
389 // For each drive, we SIBO_PARSE with its drive letter to get a response
390 // (which we ignore), then do a SIBO_STATUSDEVICE to get the info.
391
392 a.init();
393 a.addByte(toupper(drive)); // Name 1
394 a.addByte(':');
395 a.addByte(0x00);
396
397 a.addByte(0x00); // No name 2
398 a.addByte(0x00); // No name 3
399 if (!sendCommand(SIBO_PARSE, a)) {
400 return E_PSI_FILE_DISC;
401 }
402 if ((res = getResponse(a)) != E_PSI_GEN_NONE) {
403 return res;
404 }
405
406 a.init();
407 a.addByte(toupper(drive)); // Name 1
408 a.addByte(':');
409 a.addByte('\\');
410 a.addByte(0x00);
412 return E_PSI_FILE_DISC;
413 }
414 if ((res = getResponse(a)) != E_PSI_GEN_NONE) {
415 return res;
416 }
417
418 int attr = a.getWord(2);
419 attr = sibo_dattr[a.getWord(2) & 0xff];
420 dinfo.setMediaType(static_cast<MediaType>(attr));
421
422 attr = a.getWord(2);
423 int changeable = a.getWord(4) ? 32 : 0;
424 int internal = (attr & 0x2000) ? 16 : 0;
425
426 dinfo.setDriveAttributes(changeable | internal);
427
428 int variable = (attr & 0x4000) ? 1 : 0;
429 int dualdens = (attr & 0x1000) ? 2 : 0;
430 int formattable = (attr & 0x0800) ? 4 : 0;
431 int protect = ((attr & 0xff) == 6) ? 8 : 0;
432
433 dinfo.setMediaAttributes(variable|dualdens|formattable|protect);
434
435 dinfo.setUID(0);
436 dinfo.setSize(a.getDWord(6), 0);
437 dinfo.setSpace(a.getDWord(10), 0);
438
439 dinfo.setName(toupper(drive), a.getString(14));
440
441 return res;
442}
443
445 if (status_ == E_PSI_FILE_DISC) {
446 reconnect();
447 if (status_ == E_PSI_FILE_DISC) {
448 return false;
449 }
450 }
451
452 bool result;
454 a.addWord(cc);
455 a.addWord(data.getLen());
456 a.addBuff(data);
457 result = socket_->sendBufferStore(a);
458 if (!result) {
459 reconnect();
460 result = socket_->sendBufferStore(a);
461 if (!result) {
463 }
464 }
465 return result;
466}
467
468
470 // getWord(2) is the size field
471 // which is the body of the response not counting the command (002a) and
472 // the size word.
473 if (socket_->getBufferStore(data) != 1) {
474 cerr << "RFSV16::getResponse: duff response. "
475 "getBufferStore failed." << endl;
476 } else if (data.getWord(0) == 0x2a &&
477 data.getWord(2) == data.getLen()-4) {
478 Enum<RFSV::errs> ret = static_cast<enum errs>(static_cast<int16_t>(data.getWord(4)));
479 data.discardFirstBytes(6);
480 return ret;
481 } else {
482 cerr << "RFSV16::getResponse: duff response. Size field:" <<
483 data.getWord(2) << " Frame size:" <<
484 data.getLen()-4 << " Result field:" <<
485 data.getWord(4) << endl;
486 }
488 return status_;
489}
490
491Enum<RFSV::errs> RFSV16::fread(const uint32_t handle, unsigned char * const buf, const uint32_t len, uint32_t &count) {
493 unsigned char *p = buf;
494 long l;
495
496 count = 0;
497 do {
499
500 // Read in blocks of 291 bytes; the maximum payload for
501 // an RFSV frame. ( As seen in traces ) - this isn't optimal:
502 // RFSV can handle fragmentation of frames, where only the
503 // first SIBO_FREAD RESPONSE frame has a RESPONSE (00 2A), SIZE
504 // and RESULT field. Every subsequent frame
505 // just has data, 297 bytes (or less) of it.
506 //
507 a.addWord(handle);
508 a.addWord((len - count) > RFSV16_MAXDATALEN
510 : (len - count));
511 if (!sendCommand(SIBO_FREAD, a)) {
512 return E_PSI_FILE_DISC;
513 }
514 if ((res = getResponse(a)) != E_PSI_GEN_NONE) {
515 if (res == E_PSI_FILE_EOF) {
516 return E_PSI_GEN_NONE;
517 }
518 return res;
519 }
520 if ((l = a.getLen()) > 0) {
521 memcpy(p, a.getString(), l);
522 count += l;
523 p += l;
524 }
525 } while ((count < len) && (l > 0));
526 return res;
527}
528
529Enum<RFSV::errs> RFSV16::fwrite(const uint32_t handle,
530 const unsigned char *const buf,
531 const uint32_t len,
532 uint32_t &count) {
534 const unsigned char *p = buf;
535
536 count = 0;
537 while (count < len) {
539 int nbytes;
540
541 // Write in blocks of 291 bytes; the maximum payload for
542 // an RFSV frame. ( As seen in traces ) - this isn't optimal:
543 // RFSV can handle fragmentation of frames, where only the
544 // first SIBO_FREAD RESPONSE frame has a RESPONSE (00 2A), SIZE
545 // and RESULT field. Every subsequent frame
546 // just has data, 297 bytes (or less) of it.
547 nbytes = (len - count) > RFSV16_MAXDATALEN
549 : (len - count);
550 a.addWord(handle);
551 a.addBytes(p, nbytes);
552 if (!sendCommand(SIBO_FWRITE, a)) {
553 return E_PSI_FILE_DISC;
554 }
555 if ((res = getResponse(a)) != E_PSI_GEN_NONE) {
556 return res;
557 }
558
559 count += nbytes;
560 p += nbytes;
561 }
562 return res;
563}
564
565Enum<RFSV::errs> RFSV16::copyFromPsion(const char *from, const char *to, void *ptr, cpCallback_t cb) {
567 uint32_t handle;
568 uint32_t len;
569 uint32_t total = 0;
570
571 if ((res = fopen(P_FSHARE | P_FSTREAM, from, handle)) != E_PSI_GEN_NONE)
572 return res;
573 ofstream op(to);
574 if (!op) {
575 fclose(handle);
576 return E_PSI_GEN_FAIL;
577 }
578 do {
579 unsigned char buf[RFSV_SENDLEN];
580 if ((res = fread(handle, buf, sizeof(buf), len)) == E_PSI_GEN_NONE) {
581 if (len > 0) {
582 op.write(reinterpret_cast<char *>(buf), static_cast<std::streamsize>(len));
583 }
584 total += len;
585 if (cb && !cb(ptr, total)) {
586 res = E_PSI_FILE_CANCEL;
587 }
588 }
589 } while (len > 0 && (res == E_PSI_GEN_NONE));
590
591 fclose(handle);
592 op.close();
593 if (res == E_PSI_FILE_EOF) {
594 res = E_PSI_GEN_NONE;
595 }
596 return res;
597}
598
601 uint32_t handle;
602 uint32_t len;
603 uint32_t total = 0;
604
605 if ((res = fopen(P_FSHARE | P_FSTREAM, from, handle)) != E_PSI_GEN_NONE) {
606 return res;
607 }
608 do {
609 unsigned char buf[RFSV_SENDLEN];
610 if ((res = fread(handle, buf, sizeof(buf), len)) == E_PSI_GEN_NONE) {
611 if (len > 0)
612 // FIXME: return UNIX errors from this method.
613 ignore_value(write(fd, buf, len));
614 total += len;
615 if (cb && !cb(NULL, total)) {
616 res = E_PSI_FILE_CANCEL;
617 }
618 }
619 } while (len > 0 && (res == E_PSI_GEN_NONE));
620
621 fclose(handle);
622 if (res == E_PSI_FILE_EOF) {
623 res = E_PSI_GEN_NONE;
624 }
625 return res;
626}
627
628Enum<RFSV::errs> RFSV16::copyToPsion(const char *from, const char *to, void *ptr, cpCallback_t cb) {
629 uint32_t handle;
630 uint32_t len = 0;
631 uint32_t total = 0;
633
634 ifstream ip(from);
635 if (!ip) {
636 return E_PSI_FILE_NXIST;
637 }
638 res = fcreatefile(P_FSTREAM | P_FUPDATE, to, handle);
639 if (res != E_PSI_GEN_NONE) {
640 res = freplacefile(P_FSTREAM | P_FUPDATE, to, handle);
641 if (res != E_PSI_GEN_NONE) {
642 return res;
643 }
644 }
645 unsigned char *buff = new unsigned char[RFSV_SENDLEN];
646 while (res == E_PSI_GEN_NONE && ip && !ip.eof()) {
647 ip.read(reinterpret_cast<char *>(buff), RFSV_SENDLEN);
648 if ((res = fwrite(handle, buff, ip.gcount(), len)) == E_PSI_GEN_NONE) {
649 total += len;
650 if (cb && !cb(ptr, total)) {
651 res = E_PSI_FILE_CANCEL;
652 }
653 }
654 }
655 delete[]buff;
656 fclose(handle);
657 ip.close();
658 return res;
659}
660
661Enum<RFSV::errs> RFSV16::copyOnPsion(const char *from, const char *to, void *ptr, cpCallback_t cb) {
662 uint32_t handle_from;
663 uint32_t handle_to;
664 uint32_t len;
665 uint32_t wlen;
666 uint32_t total = 0;
668
669 if ((res = fopen(P_FSHARE | P_FSTREAM, from, handle_from)) != E_PSI_GEN_NONE) {
670 return res;
671 }
672 res = fcreatefile(P_FSTREAM | P_FUPDATE, to, handle_to);
673 if (res != E_PSI_GEN_NONE) {
674 res = freplacefile(P_FSTREAM | P_FUPDATE, to, handle_to);
675 if (res != E_PSI_GEN_NONE) {
676 return res;
677 }
678 }
679 do {
680 unsigned char buf[RFSV_SENDLEN];
681 if ((res = fread(handle_from, buf, sizeof(buf), len)) == E_PSI_GEN_NONE) {
682 if (len > 0) {
683 if ((res = fwrite(handle_to, buf, len, wlen)) == E_PSI_GEN_NONE) {
684 total += wlen;
685 if (cb && !cb(ptr, total)) {
686 res = E_PSI_FILE_CANCEL;
687 }
688 }
689 }
690 }
691 } while (len > 0 && wlen > 0 && (res == E_PSI_GEN_NONE));
692 fclose(handle_from);
693 fclose(handle_to);
694 if (res == E_PSI_FILE_EOF) {
695 res = E_PSI_GEN_NONE;
696 }
697 return res;
698}
699
700Enum<RFSV::errs> RFSV16::pathtest(const char * const path) {
701 string realName = convertSlash(path);
703 a.addStringT(realName.c_str());
705 return getResponse(a);
706}
707
708Enum<RFSV::errs> RFSV16::fsetsize(uint32_t handle, uint32_t size) {
710 a.addWord(handle & 0xffff);
711 a.addDWord(size);
712 if (!sendCommand(SIBO_FSETEOF, a)) {
713 return E_PSI_FILE_DISC;
714 }
715 return getResponse(a);
716}
717
718/*
719 * Unix-like implementation off fseek with one
720 * exception: If seeking beyond eof, the gap
721 * contains garbage instead of zeroes.
722 */
723Enum<RFSV::errs> RFSV16::fseek(const uint32_t handle, const int32_t pos, const uint32_t mode, uint32_t &resultpos) {
726 uint32_t savpos = 0;
727 uint32_t realpos;
728 uint32_t calcpos = 0;
729
730/*
731 seek-parameter for psion:
732 dword position
733 dword handle
734 dword mode
735 1 = from start
736 2 = from current pos
737 3 = from end
738 ??no more?? 4 = sense recpos
739 ??no more?? 5 = set recpos
740 ??no more?? 6 = text-rewind
741*/
742
743 if ((mode < PSI_SEEK_SET) || (mode > PSI_SEEK_END)) {
744 return E_PSI_GEN_ARG;
745 }
746
747 if ((mode == PSI_SEEK_CUR) && (pos >= 0)) {
748 /* get and save current position */
749 a.init();
750 a.addWord(handle);
751 a.addDWord(0);
752 a.addWord(PSI_SEEK_CUR);
753 if (!sendCommand(SIBO_FSEEK, a)) {
754 return E_PSI_FILE_DISC;
755 }
756 if ((res = getResponse(a)) != E_PSI_GEN_NONE) {
757 return res;
758 }
759 savpos = a.getDWord(0);
760 if (pos == 0) {
761 resultpos = savpos;
762 return res;
763 }
764 }
765 if ((mode == PSI_SEEK_END) && (pos >= 0)) {
766 /* get and save end position */
767 a.init();
768 a.addWord(handle);
769 a.addDWord(0);
770 a.addWord(PSI_SEEK_END);
771 if (!sendCommand(SIBO_FSEEK, a)) {
772 return E_PSI_FILE_DISC;
773 }
774 if ((res = getResponse(a)) != E_PSI_GEN_NONE) {
775 return res;
776 }
777 savpos = a.getDWord(0);
778 if (pos == 0) {
779 resultpos = savpos;
780 return res;
781 }
782 }
783 /* Now the real seek */
784 a.addWord(handle);
785 a.addDWord(pos);
786 a.addWord(mode);
787 if (!sendCommand(SIBO_FSEEK, a)) {
788 return E_PSI_FILE_DISC;
789 }
790 if ((res = getResponse(a)) != 0) {
791 return res;
792 }
793 realpos = a.getDWord(0);
794 switch (mode) {
795 case PSI_SEEK_SET:
796 calcpos = pos;
797 break;
798 case PSI_SEEK_CUR:
799 calcpos = savpos + pos;
800 break;
801 case PSI_SEEK_END:
802 resultpos = realpos;
803 return res;
804 break;
805 }
806 if (calcpos > realpos) {
807 /* Beyond end of file */
808 res = fsetsize(handle, calcpos);
809 if (res != E_PSI_GEN_NONE) {
810 return res;
811 }
812 a.init();
813 a.addWord(handle);
814 a.addDWord(calcpos);
815 a.addWord(PSI_SEEK_SET);
816 if (!sendCommand(SIBO_FSEEK, a)) {
817 return E_PSI_FILE_DISC;
818 }
819 if ((res = getResponse(a)) != 0) {
820 return res;
821 }
822 realpos = a.getDWord(0);
823 }
824 resultpos = realpos;
825 return res;
826}
827
828Enum<RFSV::errs> RFSV16::mkdir(const char* dirName) {
829 string realName = convertSlash(dirName);
831 a.addStringT(realName.c_str());
833 return getResponse(a);
834}
835
836Enum<RFSV::errs> RFSV16::rmdir(const char *dirName) {
837 // EPOC16 doesn't provide an RMDIR command, so we fake it using DELETE (and a few little tweaks).
838
839 // Rudimentary argument checking.
840 string path(dirName);
841 if (path.empty()) {
842 return E_PSI_FILE_NAME;
843 }
844
845 // The EPOC32 implementation of RMDIR allows for deletion of paths with or without a trailing forward slash.
846 // However, EPOC16's DELETE (which we use here) doesn't like these, so we strip them to ensure parity between the
847 // two implementations.
848 if (path.back() == '\\') {
849 path.pop_back();
850 }
851
852 // Get the path's attributes and ensure it's a directory.
853 uint32_t attr;
854 Enum<RFSV::errs> res = fgetattr(path.c_str(), attr);
855 if (res != E_PSI_GEN_NONE) {
856 return res;
857 }
858 if ((attr & PSI_A_DIR) == 0) {
859 return E_PSI_FILE_DIR;
860 }
861
862 return remove(path.c_str());
863}
864
865Enum<RFSV::errs> RFSV16::rename(const char *oldName, const char *newName) {
866 string realOldName = convertSlash(oldName);
867 string realNewName = convertSlash(newName);
869 a.addStringT(realOldName.c_str());
870 a.addStringT(realNewName.c_str());
872 return getResponse(a);
873}
874
875Enum<RFSV::errs> RFSV16::remove(const char* psionName) {
876 string realName = convertSlash(psionName);
878 a.addStringT(realName.c_str());
879 // and this needs sending in the length word.
881 return getResponse(a);
882}
883
884Enum<RFSV::errs> RFSV16::setVolumeName(const char drive , const char * const name) {
885 (void)drive;
886 (void)name;
887 // Not yet ...
888 return E_PSI_GEN_FAIL;
889}
890
891/*
892 * Translate SIBO attributes to standard attributes.
893 */
894uint32_t RFSV16::attr2std(uint32_t attr) {
895 uint32_t res = 0;
896
897 // Common attributes
898 if (!(attr & P_FAWRITE)) {
899 res |= PSI_A_RDONLY;
900 }
901 if (attr & P_FAHIDDEN) {
902 res |= PSI_A_HIDDEN;
903 }
904 if (attr & P_FASYSTEM) {
905 res |= PSI_A_SYSTEM;
906 }
907 if (attr & P_FADIR) {
908 res |= PSI_A_DIR;
909 }
910 if (attr & P_FAMOD) {
911 res |= PSI_A_ARCHIVE;
912 }
913 if (attr & P_FAVOLUME) {
914 res |= PSI_A_VOLUME;
915 }
916
917 // SIBO-specific
918 if (attr & P_FAREAD) {
919 res |= PSI_A_READ;
920 }
921 if (attr & P_FAEXEC) {
922 res |= PSI_A_EXEC;
923 }
924 if (attr & P_FASTREAM) {
925 res |= PSI_A_STREAM;
926 }
927 if (attr & P_FATEXT) {
928 res |= PSI_A_TEXT;
929 }
930
931 // Do what we can for EPOC
932 res |= PSI_A_NORMAL;
933
934 return res;
935}
936
937/*
938 * Translate standard attributes to SIBO attributes.
939 */
940uint32_t RFSV16::std2attr(const uint32_t attr) {
941 uint32_t res = 0;
942
943 // Common attributes
944 if (!(attr & PSI_A_RDONLY)) {
945 res |= P_FAWRITE;
946 }
947 if (attr & PSI_A_HIDDEN) {
948 res |= P_FAHIDDEN;
949 }
950 if (attr & PSI_A_SYSTEM) {
951 res |= P_FASYSTEM;
952 }
953 if (attr & PSI_A_DIR) {
954 res |= P_FADIR;
955 }
956 if (attr & PSI_A_ARCHIVE) {
957 res |= P_FAMOD;
958 }
959 if (attr & PSI_A_VOLUME) {
960 res |= P_FAVOLUME;
961 }
962
963 // SIBO-specific
964 if (attr & PSI_A_READ) {
965 res |= P_FAREAD;
966 }
967 if (attr & PSI_A_EXEC) {
968 res |= P_FAEXEC;
969 }
970 if (attr & PSI_A_STREAM) {
971 res |= P_FASTREAM;
972 }
973 if (attr & PSI_A_TEXT) {
974 res |= P_FATEXT;
975 }
976
977 return res;
978}
A generic container for an array of bytes.
Definition: bufferstore.h:36
const char * getString(long pos=0) const
Retrieves the characters at index pos.
Definition: bufferstore.cc:118
uint16_t getWord(long pos=0) const
Retrieves the word at index pos.
Definition: bufferstore.cc:100
uint32_t getDWord(long pos=0) const
Retrieves the dword at index pos.
Definition: bufferstore.cc:104
void addWord(int w)
Appends a word to the content of this instance.
Definition: bufferstore.cc:191
unsigned long getLen() const
Retrieves the length of a BufferStore.
Definition: bufferstore.cc:92
void discardFirstBytes(int len=0)
Removes bytes from the start of the buffer.
Definition: bufferstore.cc:141
void init()
Initializes the BufferStore.
Definition: bufferstore.cc:74
A class representing information about a Disk drive on the psion.
Definition: drive.h:51
void setSpace(uint32_t spaceLo, uint32_t spaceHi)
Definition: drive.cc:72
void setName(char drive, const char *const volname)
Definition: drive.cc:76
void setUID(uint32_t uid)
Definition: drive.cc:64
void setMediaType(MediaType type)
Definition: drive.cc:52
void setDriveAttributes(uint32_t driveAttribute)
Definition: drive.cc:56
void setMediaAttributes(uint32_t mediaAttribute)
Definition: drive.cc:60
void setSize(uint32_t sizeLo, uint32_t sizeHi)
Definition: drive.cc:68
Wrapper class featuring range-checking and string representation of enumerated values.
Definition: Enum.h:135
A class, representing a directory entry of the Psion.
Definition: plpdirent.h:79
std::string dirname_
Definition: plpdirent.h:199
std::string attrstr
Definition: plpdirent.h:198
PsiTime time
Definition: plpdirent.h:197
std::string name
Definition: plpdirent.h:200
PlpUID UID
Definition: plpdirent.h:196
uint32_t attr
Definition: plpdirent.h:195
uint32_t size
Definition: plpdirent.h:194
A class, representing the UIDs of a file on the Psion.
Definition: plpdirent.h:41
Psion time related utility class.
Definition: psitime.h:124
uint32_t getSiboTime()
Retrieves the instance's current value in SIBO time format.
Definition: psitime.cc:246
void setSiboTime(uint32_t stime)
Modifies the value of this instance.
Definition: psitime.cc:237
Enum< RFSV::errs > mktemp(uint32_t &, std::string &)
Creates a unique temporary file.
Definition: rfsv16.cc:72
Enum< RFSV::errs > getResponse(BufferStore &)
Definition: rfsv16.cc:469
Enum< RFSV::errs > devlist(uint32_t &)
Retrieves available drives on the Psion.
Definition: rfsv16.cc:311
@ P_FATEXT
Definition: rfsv16.h:129
@ P_FAEXEC
Definition: rfsv16.h:127
@ P_FAVOLUME
Definition: rfsv16.h:123
@ P_FAREAD
Definition: rfsv16.h:126
@ P_FAHIDDEN
Definition: rfsv16.h:121
@ P_FAWRITE
Definition: rfsv16.h:120
@ P_FADIR
Definition: rfsv16.h:124
@ P_FASTREAM
Definition: rfsv16.h:128
@ P_FAMOD
Definition: rfsv16.h:125
@ P_FASYSTEM
Definition: rfsv16.h:122
Enum< RFSV::errs > fseek(const uint32_t, const int32_t, const uint32_t, uint32_t &)
Sets the current file position of a file on the Psion.
Definition: rfsv16.cc:723
Enum< RFSV::errs > freplacefile(const uint32_t, const char *const, uint32_t &)
Creates an named file, overwriting an existing file.
Definition: rfsv16.cc:94
commands
Definition: rfsv16.h:76
@ SIBO_DELETE
Definition: rfsv16.h:87
@ SIBO_PATHTEST
Definition: rfsv16.h:94
@ SIBO_OPENUNIQUE
Definition: rfsv16.h:92
@ SIBO_RENAME
Definition: rfsv16.h:86
@ SIBO_MKDIR
Definition: rfsv16.h:91
@ SIBO_FDIRREAD
Definition: rfsv16.h:80
@ SIBO_SFDATE
Definition: rfsv16.h:97
@ SIBO_PARSE
Definition: rfsv16.h:90
@ SIBO_FSETEOF
Definition: rfsv16.h:85
@ SIBO_SFSTAT
Definition: rfsv16.h:89
@ SIBO_FDEVICEREAD
Definition: rfsv16.h:81
@ SIBO_FREAD
Definition: rfsv16.h:79
@ SIBO_FCLOSE
Definition: rfsv16.h:78
@ SIBO_STATUSDEVICE
Definition: rfsv16.h:93
@ SIBO_FINFO
Definition: rfsv16.h:88
@ SIBO_FWRITE
Definition: rfsv16.h:82
@ SIBO_FOPEN
Definition: rfsv16.h:77
@ SIBO_FSEEK
Definition: rfsv16.h:83
Enum< RFSV::errs > fsetsize(const uint32_t, const uint32_t)
Resizes an open file on the Psion.
Definition: rfsv16.cc:708
Enum< RFSV::errs > copyOnPsion(const char *, const char *, void *, cpCallback_t)
Copies a file from the Psion to the Psion.
Definition: rfsv16.cc:661
Enum< RFSV::errs > rmdir(const char *const)
Removes a directory on the Psion.
Definition: rfsv16.cc:836
Enum< RFSV::errs > closedir(RFSVDirHandle &)
Close a directory, previously opened with opendir.
Definition: rfsv16.cc:121
Enum< RFSV::errs > readdir(RFSVDirHandle &, PlpDirent &)
Read directory entries.
Definition: rfsv16.cc:125
Enum< RFSV::errs > fclose(const uint32_t)
Close a file on the Psion whih was previously opened/created by using fopen , fcreatefile ,...
Definition: rfsv16.cc:102
Enum< RFSV::errs > fopendir(const char *const, uint32_t &)
Definition: rfsv16.cc:98
Enum< RFSV::errs > setVolumeName(const char, const char *const)
Set the name of a Psion Volume (Drive).
Definition: rfsv16.cc:884
Enum< RFSV::errs > fopen(const uint32_t, const char *const, uint32_t &)
Opens a file.
Definition: rfsv16.cc:53
Enum< RFSV::errs > fsetattr(const char *const, const uint32_t seta, const uint32_t unseta)
Definition: rfsv16.cc:280
Enum< RFSV::errs > fwrite(const uint32_t, const unsigned char *const, const uint32_t, uint32_t &)
Write to a file on the Psion.
Definition: rfsv16.cc:529
Enum< RFSV::errs > rename(const char *const, const char *const)
Renames a file on the Psion.
Definition: rfsv16.cc:865
Enum< RFSV::errs > dir(const char *const, PlpDir &)
Reads a directory on the Psion.
Definition: rfsv16.cc:161
Enum< RFSV::errs > opendir(const uint32_t, const char *const, RFSVDirHandle &)
Open a directory for reading with readdir.
Definition: rfsv16.cc:111
Enum< RFSV::errs > fgetmtime(const char *const, PsiTime &)
Retrieves the modification time of a file on the Psion.
Definition: rfsv16.cc:192
uint32_t std2attr(const uint32_t)
Definition: rfsv16.cc:940
Enum< RFSV::errs > mkdir(const char *const)
Creates a directory on the Psion.
Definition: rfsv16.cc:828
Enum< RFSV::errs > fcreatefile(const uint32_t, const char *const, uint32_t &)
Creates a named file.
Definition: rfsv16.cc:90
Enum< RFSV::errs > fsetmtime(const char *const, const PsiTime)
Sets the modification time of a file on the Psion.
Definition: rfsv16.cc:212
Enum< RFSV::errs > copyFromPsion(const char *const, const char *const, void *, cpCallback_t)
Copies a file from the Psion to the local machine.
Definition: rfsv16.cc:565
Enum< RFSV::errs > dircount(const char *const, uint32_t &)
Counts number of entries in a directory.
Definition: rfsv16.cc:294
bool sendCommand(enum commands, BufferStore &)
Definition: rfsv16.cc:444
Enum< RFSV::errs > fgeteattr(const char *const, PlpDirent &)
Retrieves attributes, size and modification time of a file on the Psion.
Definition: rfsv16.cc:246
Enum< RFSV::errs > fread(const uint32_t, unsigned char *const, const uint32_t, uint32_t &)
Reads from a file on the Psion.
Definition: rfsv16.cc:491
RFSV16(std::unique_ptr< TCPSocket > socket)
Definition: rfsv16.cc:46
Enum< RFSV::errs > fgetattr(const char *const, uint32_t &)
Retrieves attributes of a file on the Psion.
Definition: rfsv16.cc:228
Enum< RFSV::errs > copyToPsion(const char *const, const char *const, void *, cpCallback_t)
Copies a file from local machine to the Psion.
Definition: rfsv16.cc:628
uint32_t attr2std(const uint32_t)
Definition: rfsv16.cc:894
Enum< RFSV::errs > pathtest(const char *const)
Checks to see if the directory component of a path or file name exists and is valid.
Definition: rfsv16.cc:700
uint32_t opMode(const uint32_t)
Converts an open-mode (A combination of the PSI_O_ constants.) from generic representation to the mac...
Definition: rfsv16.cc:179
Enum< RFSV::errs > remove(const char *const)
Removes a file on the Psion.
Definition: rfsv16.cc:875
Enum< RFSV::errs > devinfo(const char, Drive &)
Retrieves details about a drive.
Definition: rfsv16.cc:384
@ P_FREPLACE
Definition: rfsv16.h:104
@ P_FUPDATE
Definition: rfsv16.h:114
@ P_FAPPEND
Definition: rfsv16.h:105
@ P_FCREATE
Definition: rfsv16.h:103
@ P_FSTREAM
Definition: rfsv16.h:107
@ P_FDEVICE
Definition: rfsv16.h:112
@ P_FUNIQUE
Definition: rfsv16.h:106
@ P_FDIR
Definition: rfsv16.h:110
@ P_FRANDOM
Definition: rfsv16.h:115
@ P_FSHARE
Definition: rfsv16.h:116
A helper class for storing intermediate internal information in RFSV16 and RFSV32 .
Definition: rfsv.h:56
uint32_t h
Definition: rfsv.h:61
BufferStore b
Definition: rfsv.h:62
std::string name_
Definition: rfsv.h:63
@ PSI_O_RDONLY
Definition: rfsv.h:94
std::string attr2String(const uint32_t attr)
Converts a file attribute RFSV::file_attribs to human readable format, usable for showing them in dir...
Definition: rfsv.cc:156
@ PSI_SEEK_SET
Definition: rfsv.h:85
@ PSI_SEEK_END
Definition: rfsv.h:87
@ PSI_SEEK_CUR
Definition: rfsv.h:86
Enum< errs > status_
Definition: rfsv.h:661
void reset()
Definition: rfsv.cc:133
void reconnect()
Definition: rfsv.cc:127
std::unique_ptr< TCPSocket > socket_
Definition: rfsv.h:660
int32_t operationId_
Definition: rfsv.h:662
static std::string convertSlash(const std::string &name)
Utility method, converts '/' to '\'.
Definition: rfsv.cc:149
errs
The known error codes.
Definition: rfsv.h:113
@ E_PSI_GEN_ARG
Definition: rfsv.h:116
@ E_PSI_FILE_DIR
Definition: rfsv.h:148
@ E_PSI_GEN_FAIL
Definition: rfsv.h:115
@ E_PSI_FILE_DISC
Definition: rfsv.h:156
@ E_PSI_FILE_CANCEL
Definition: rfsv.h:154
@ E_PSI_FILE_NXIST
Definition: rfsv.h:139
@ E_PSI_FILE_NAME
Definition: rfsv.h:144
@ E_PSI_GEN_NONE
Definition: rfsv.h:114
@ E_PSI_FILE_EOF
Definition: rfsv.h:142
@ PSI_A_NORMAL
Attributes, valid on EPOC only.
Definition: rfsv.h:207
@ PSI_A_TEXT
Definition: rfsv.h:215
@ PSI_A_ARCHIVE
Definition: rfsv.h:203
@ PSI_A_DIR
Definition: rfsv.h:202
@ PSI_A_EXEC
Definition: rfsv.h:213
@ PSI_A_HIDDEN
Definition: rfsv.h:200
@ PSI_A_READ
Attributes, valid on SIBO only.
Definition: rfsv.h:212
@ PSI_A_STREAM
Definition: rfsv.h:214
@ PSI_A_VOLUME
Definition: rfsv.h:204
@ PSI_A_RDONLY
Attributes, valid on both EPOC and SIBO.
Definition: rfsv.h:199
@ PSI_A_SYSTEM
Definition: rfsv.h:201
@ PSI_O_APPEND
Definition: rfsv.h:106
@ PSI_O_CREAT
Definition: rfsv.h:103
@ PSI_O_TRUNC
Definition: rfsv.h:105
@ PSI_O_EXCL
Definition: rfsv.h:104
MediaType
Definition: drive.h:31
Definition: doctest.h:522
static RFSV * a
Definition: main.cc:55
static int sibo_dattr[]
Definition: rfsv16.cc:374
#define RFSV16_MAXDATALEN
Definition: rfsv16.cc:42
int(* cpCallback_t)(void *, uint32_t)
Defines the callback procedure for progress indication of copy operations.
Definition: rfsv.h:45
std::deque< class PlpDirent > PlpDir
Definition: rfsv.h:34
const int RFSV_SENDLEN
Definition: rfsv.h:39