plptools
Loading...
Searching...
No Matches
main.cc
Go to the documentation of this file.
1/*
2 * This file is part of plptools.
3 *
4 * Copyright (C) 1999-2001 Fritz Elfert <felfert@to.com>
5 * Copyright (C) 2007 Reuben Thomas <rrt@sc3d.org>
6 * Copyright (C) 2026 Syed Shahrukh Hussain <syed.shahrukh@ossrevival.org>
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
23#include "config.h"
24
25#include <bufferarray.h>
26#include <bufferstore.h>
27#include <cliutils.h>
28#include <cstdint>
29#include <drive.h>
30#include <rfsv.h>
31#include <rfsvfactory.h>
32#include <rpcs.h>
33#include <rpcsfactory.h>
34#include <tcpsocket.h>
35
36#include <iostream>
37#include <string>
38
39#include <stdlib.h>
40#include <stdio.h>
41#include <signal.h>
42#include <unistd.h>
43#include <errno.h>
44
45#include "rfsv_api.h"
46
47#ifndef _GNU_SOURCE
48#define _GNU_SOURCE
49#endif
50#include <getopt.h>
51
52#if FUSE_USE_VERSION >= 30
53#include <fuse3/fuse_lowlevel.h>
54#else
55#include <fuse/fuse_lowlevel.h>
56#endif
57
58using namespace std;
59
60static RFSV *a;
62
63static RPCS *r;
66
67/* Translate EPOC/SIBO error to UNIX error code, leaving positive
68 numbers alone */
69int epocerr_to_errno(long epocerr) {
70 int unixerr = (int)epocerr;
71
72 if (epocerr < 0) {
73 switch (epocerr) {
75 unixerr = 0;
76 break;
78 unixerr = -EEXIST;
79 break;
82 unixerr = -ENOENT;
83 break;
86 case RFSV::E_PSI_FILE_EOF: // Can't err = EOF as it's not an error code
87 case RFSV::E_PSI_FILE_ALLOC: // FIXME: No idea what this is
90 unixerr = -EPERM;
91 break;
93 unixerr = -ENOSPC;
94 break;
98 unixerr = -EINVAL;
99 break;
104 unixerr = -EACCES;
105 break;
110 unixerr = -EBUSY;
111 break;
126 default:
127 unixerr = -EIO;
128 break;
130 unixerr = -EINTR;
131 break;
134 unixerr = -ENODEV;
135 break;
137 unixerr = -EFBIG;
138 break;
140 unixerr = -EBADF;
141 break;
142 }
143 }
144
145 debuglog("EPOC error %ld became UNIX code %d", epocerr, unixerr);
146 return unixerr;
147}
148
149int rfsv_isalive(void) {
150 if (!a) {
151 if (!(a = rf->create(true)))
152 return 0;
153 }
154 return a->getStatus() == RFSV::E_PSI_GEN_NONE;
155}
156
157int rfsv_dir(const char *file, dentry **e) {
158 PlpDir entries;
159 dentry *tmp;
160 long ret;
161
162 if (!a)
163 return -ENODEV;
164 ret = a->dir(file, entries);
165
166 for (int i = 0; i < entries.size(); i++) {
167 PlpDirent pe = entries[i];
168 tmp = *e;
169 *e = (dentry *)calloc(1, sizeof(dentry));
170 if (!*e)
171 return -ENODEV;
172 (*e)->time = pe.getPsiTime().getTime();
173 (*e)->size = pe.getSize();
174 (*e)->attr = pe.getAttr();
175 (*e)->name = strdup(pe.getName());
176 (*e)->next = tmp;
177 }
178 return epocerr_to_errno(ret);
179}
180
181int rfsv_dircount(const char *file, uint32_t *count) {
182 if (!a)
183 return -ENODEV;
184 return epocerr_to_errno(a->dircount(file, *count));
185}
186
187int rfsv_rmdir(const char *name) {
188 if (!a)
189 return -ENODEV;
190 return epocerr_to_errno(a->rmdir(name));
191}
192
193int rfsv_mkdir(const char *file) {
194 if (!a)
195 return -ENODEV;
196 return epocerr_to_errno(a->mkdir(file));
197}
198
199int rfsv_remove(const char *file) {
200 if (!a)
201 return -ENODEV;
202 return epocerr_to_errno(a->remove(file));
203}
204
205int rfsv_fclose(long handle) {
206 if (!a)
207 return -ENODEV;
208 return epocerr_to_errno(a->fclose(handle));
209}
210
211int rfsv_fcreate(long attr, const char *file, uint32_t *handle) {
212 uint32_t ph;
213 long ret;
214
215 if (!a)
216 return -ENODEV;
217 ret = a->fcreatefile(attr, file, ph);
218 *handle = ph;
219 return epocerr_to_errno(ret);
220}
221
222int rfsv_open(const char *name, long mode, uint32_t *handle) {
223 long ret, retry;
224
225 if (!a)
226 return -ENODEV;
227 if (mode == O_RDONLY)
228 mode = RFSV::PSI_O_RDONLY;
229 else
230 mode = RFSV::PSI_O_RDWR;
231 for (retry = 100; retry > 0 && (ret = a->fopen(a->opMode(mode), name, *handle)) != RFSV::E_PSI_GEN_NONE; retry--)
232 usleep(20000);
233 return epocerr_to_errno(ret);
234}
235
236int rfsv_read(char *buf, long offset, long len, const char *name) {
237 uint32_t ret = 0, r_offset, handle;
238
239 if (!a)
240 return -ENODEV;
241 if ((ret = rfsv_open(name, O_RDONLY, &handle)))
242 return ret;
243 if (a->fseek(handle, offset, RFSV::PSI_SEEK_SET, r_offset) != RFSV::E_PSI_GEN_NONE ||
244 offset != r_offset ||
245 a->fread(handle, (unsigned char *)buf, len, ret) != RFSV::E_PSI_GEN_NONE)
246 ret = -1;
247 rfsv_fclose(handle);
248 return epocerr_to_errno(ret);
249}
250
251int rfsv_write(const char *buf, long offset, long len, const char *name) {
252 uint32_t ret = 0, r_offset, handle;
253
254 if (!a)
255 return -ENODEV;
256 if ((ret = rfsv_open(name, O_RDWR, &handle)))
257 return ret;
258 if (a->fseek(handle, offset, RFSV::PSI_SEEK_SET, r_offset) != RFSV::E_PSI_GEN_NONE ||
259 offset != r_offset ||
260 a->fwrite(handle, (unsigned char *)buf, len, ret) != RFSV::E_PSI_GEN_NONE)
261 ret = -1;
262 rfsv_fclose(handle);
263 return epocerr_to_errno(ret);
264}
265
266int rfsv_setmtime(const char *name, long time) {
267 if (!a)
268 return -ENODEV;
269 return epocerr_to_errno(a->fsetmtime(name, PsiTime(time)));
270}
271
272int rfsv_setsize(const char *name, long size) {
273 uint32_t ph;
274 long ret;
275
276 if (!a)
277 return -ENODEV;
278 ret = a->fopen(a->opMode(RFSV::PSI_O_RDWR), name, ph);
279 if (!ret) {
280 ret = a->fsetsize(ph, size);
281 a->fclose(ph);
282 }
283 return epocerr_to_errno(ret);
284}
285
286int rfsv_setattr(const char *name, long sattr, long dattr) {
287 if (!a)
288 return -ENODEV;
289 return epocerr_to_errno(a->fsetattr(name, sattr, dattr));
290}
291
292int rfsv_getattr(const char *name, long *attr, long *size, long *time) {
293 long res;
294 PlpDirent e;
295
296 if (!a)
297 return -ENODEV;
298 res = a->fgeteattr(name, e);
299 *attr = e.getAttr();
300 *size = e.getSize();
301 *time = e.getPsiTime().getTime();
302 return epocerr_to_errno(res);
303}
304
305int rfsv_rename(const char *oldname, const char *newname) {
306 if (!a)
307 return -ENODEV;
308 return epocerr_to_errno(a->rename(oldname, newname));
309}
310
311int rfsv_drivelist(int *cnt, device **dlist) {
312 *dlist = NULL;
313 uint32_t devbits;
314 long ret;
315 int i;
316
317 if (!a)
318 return -ENODEV;
319 ret = a->devlist(devbits);
320 if (ret == 0)
321 for (i = 0; i < 26; i++) {
322 Drive drive;
323
324 if ((devbits & 1) &&
325 ((a->devinfo(i + 'A', drive) == RFSV::E_PSI_GEN_NONE))) {
326
327 device *next = *dlist;
328 *dlist = (device *)malloc(sizeof(device));
329 (*dlist)->next = next;
330 (*dlist)->name = strdup(drive.getName().c_str());
331 (*dlist)->total = drive.getSize();
332 (*dlist)->free = drive.getSpace();
333 (*dlist)->letter = 'A' + i;
334 (*dlist)->attrib = static_cast<uint32_t>(drive.getMediaType());
335 (*cnt)++;
336 }
337 devbits >>= 1;
338 }
339 return epocerr_to_errno(ret);
340}
341
342static void
344{
345 cerr << _(
346 "Usage: plpfuse [OPTION...] MOUNTPOINT\n"
347 "\n"
348 "plpfuse options:\n"
349 "\n"
350 " -d, --debug Increase debugging level\n"
351 " -h, --help Display this text\n"
352 " -V, --version Print version and exit\n"
353 " -p, --port=[HOST:]PORT Connect to port PORT on host HOST\n"
354 " Default for HOST is 127.0.0.1\n"
355 " Default for PORT is "
356 ) << DPORT << "\n\n";
357}
358
359static struct option opts[] = {
360 {"help", no_argument, nullptr, 'h'},
361 {"debug", no_argument, nullptr, 'd'},
362 {"version", no_argument, nullptr, 'V'},
363 {"port", required_argument, nullptr, 'p'},
364 {nullptr, 0, nullptr, 0 }
365};
366
367int fuse(int argc, char *argv[])
368{
369 struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
370#if FUSE_USE_VERSION >= 30
371 struct fuse_cmdline_opts opts;
372 struct fuse *fp;
373#else
374 struct fuse_chan *ch;
375 char *mountpoint;
376#endif
377 int err = -1, foreground;
378#if FUSE_USE_VERSION >= 30
379 if (fuse_parse_cmdline(&args, &opts) != -1) {
380 if (opts.mountpoint == NULL) {
381 help();
382 } else if (fuse_daemonize(opts.foreground) != -1) {
383 fp = fuse_new(&args, &plp_oper, sizeof(plp_oper), NULL);
384 if (fp != NULL && (fuse_mount(fp, opts.mountpoint)) == 0)
385 err = fuse_loop(fp);
386 fuse_unmount(fp);
387 }
388 }
389#else // fuse 2
390 if (fuse_parse_cmdline(&args, &mountpoint, NULL, &foreground) != -1 &&
391 (ch = fuse_mount(mountpoint, &args)) != NULL) {
392 if (fuse_daemonize(foreground) != -1) {
393 struct fuse *fp = fuse_new(ch, &args, &plp_oper, sizeof(plp_oper), NULL);
394 if (fp != NULL)
395 err = fuse_loop(fp);
396 }
397 fuse_unmount(mountpoint, ch);
398 }
399#endif
400 fuse_opt_free_args(&args);
401 return err ? 1 : 0;
402}
403
404int main(int argc, char**argv) {
405 string host = "127.0.0.1";
406 int sockNum = DPORT, i, c, oldoptind = 1;
407
409
410 /* N.B. Option handling is kludged. Most of the options are shared
411 with FUSE, except for -p/--port, which has to be removed from
412 argv so that FUSE doesn't see it. Hence, we don't complain
413 about unknown options, but leave that to FUSE, and similarly we
414 don't quit after issuing a version or help message. */
415 opterr = 0; // Suppress errors from unknown options
416 while ((c = getopt_long(argc, argv, "hVp:d", opts, NULL)) != -1) {
417 switch (c) {
418 case 'V':
419 cout << _("plpfuse version ") << VERSION << endl;
420 return 0;
421 case 'h':
422 help();
423 return 0;
424 case 'd':
425 debug++;
426 break;
427 case 'p':
428 if (!cli_utils::parse_port(optarg, &host, &sockNum)) {
429 cout << _("Invalid port definition.") << endl;
430 return 1;
431 }
432 argc -= optind - oldoptind;
433 for (i = oldoptind; i < argc; i++)
434 argv[i] = argv[i + (optind - oldoptind)];
435 break;
436 }
437 if (optind >= argc)
438 break;
439 }
440
441 rf = new RFSVFactory(host.c_str(), sockNum);
442 rp = new RPCSFactory(host.c_str(), sockNum);
443 a = rf->create(true);
444 r = rp->create(true);
445 if (a != NULL && r != NULL)
446 debuglog("plpfuse: connected");
447 else
448 debuglog("plpfuse: could not create rfsv or RPCS object, connect delayed");
449 return fuse(argc, argv);
450}
A generic container for an array of bytes.
Definition bufferstore.h:36
A class representing information about a Disk drive on the psion.
Definition drive.h:51
MediaType getMediaType() const
Retrieve the media type of the drive.
Definition drive.cc:82
uint64_t getSpace() const
Retrieve the free capacity on the drive.
Definition drive.cc:102
uint64_t getSize() const
Retrieve the total capacity of the drive.
Definition drive.cc:98
std::string getName() const
Retrieve the volume name of the drive.
Definition drive.cc:106
A class, representing a directory entry of the Psion.
Definition plpdirent.h:79
uint32_t getAttr() const
Retrieves the file attributes of a directory entry.
Definition plpdirent.cc:75
const char * getName() const
Retrieve the file name of a directory entry.
Definition plpdirent.cc:102
PsiTime getPsiTime()
Retrieve the modification time of a directory entry.
Definition plpdirent.cc:106
uint32_t getSize() const
Retrieves the file size of a directory entry.
Definition plpdirent.cc:71
Psion time related utility class.
Definition psitime.h:124
time_t getTime(void)
Retrieves the instance's current value in Unix time format.
Definition psitime.cc:132
A factory for automatically instantiating the correct RFSV protocol variant depending on the connecte...
Definition rfsvfactory.h:36
RFSV * create(bool, Enum< ConnectionError > *error=nullptr)
Creates a new RFSV instance.
Access remote file services of a Psion.
Definition rfsv.h:79
virtual Enum< errs > fsetsize(const uint32_t handle, const uint32_t size)=0
Resizes an open file on the Psion.
@ PSI_O_RDWR
Definition rfsv.h:96
@ PSI_O_RDONLY
Definition rfsv.h:94
virtual Enum< errs > fwrite(const uint32_t handle, const unsigned char *const buffer, const uint32_t len, uint32_t &count)=0
Write to a file on the Psion.
virtual uint32_t opMode(const uint32_t mode)=0
Converts an open-mode (A combination of the PSI_O_ constants.) from generic representation to the mac...
virtual Enum< errs > remove(const char *const name)=0
Removes a file on the Psion.
virtual Enum< errs > fseek(const uint32_t handle, const int32_t offset, const uint32_t mode, uint32_t &resultpos)=0
Sets the current file position of a file on the Psion.
virtual Enum< errs > fopen(const uint32_t attr, const char *const name, uint32_t &handle)=0
Opens a file.
virtual Enum< errs > fread(const uint32_t handle, unsigned char *const buffer, const uint32_t len, uint32_t &count)=0
Reads from a file on the Psion.
virtual Enum< errs > fsetattr(const char *const name, const uint32_t seta, const uint32_t unseta)=0
virtual Enum< errs > fgeteattr(const char *const name, PlpDirent &e)=0
Retrieves attributes, size and modification time of a file on the Psion.
virtual Enum< errs > fcreatefile(const uint32_t attr, const char *const name, uint32_t &handle)=0
Creates a named file.
virtual Enum< errs > fsetmtime(const char *const name, const PsiTime mtime)=0
Sets the modification time of a file on the Psion.
@ PSI_SEEK_SET
Definition rfsv.h:85
virtual Enum< errs > mkdir(const char *const name)=0
Creates a directory on the Psion.
virtual Enum< errs > fclose(const uint32_t handle)=0
Close a file on the Psion whih was previously opened/created by using fopen , fcreatefile ,...
Enum< errs > getStatus()
Retrieves the current connection status.
Definition rfsv.cc:145
virtual Enum< errs > dir(const char *const name, PlpDir &ret)=0
Reads a directory on the Psion.
virtual Enum< errs > dircount(const char *const name, uint32_t &count)=0
Counts number of entries in a directory.
virtual Enum< errs > rmdir(const char *const name)=0
Removes a directory on the Psion.
virtual Enum< errs > devlist(uint32_t &devbits)=0
Retrieves available drives on the Psion.
virtual Enum< errs > devinfo(const char drive, Drive &dinfo)=0
Retrieves details about a drive.
virtual Enum< errs > rename(const char *const oldname, const char *const newname)=0
Renames a file on the Psion.
@ E_PSI_FILE_TOOBIG
Definition rfsv.h:177
@ E_PSI_FILE_PENDING
Definition rfsv.h:152
@ E_PSI_FILE_ERASE
Definition rfsv.h:174
@ E_PSI_FILE_ACCESS
Definition rfsv.h:145
@ E_PSI_FILE_RDONLY
Definition rfsv.h:150
@ E_PSI_FILE_ALLOC
Definition rfsv.h:155
@ E_PSI_FILE_DIR
Definition rfsv.h:148
@ E_PSI_FILE_WRITE
Definition rfsv.h:140
@ E_PSI_GEN_INUSE
Definition rfsv.h:123
@ E_PSI_FILE_RETRAN
Definition rfsv.h:158
@ E_PSI_FILE_INACT
Definition rfsv.h:160
@ E_PSI_FILE_FULL
Definition rfsv.h:143
@ E_PSI_FILE_NDISC
Definition rfsv.h:180
@ E_PSI_FILE_EXIST
Definition rfsv.h:138
@ E_PSI_FILE_VOLUME
Definition rfsv.h:153
@ E_PSI_FILE_DEVICE
Definition rfsv.h:147
@ E_PSI_FILE_CONNECT
Definition rfsv.h:157
@ E_PSI_FILE_CORRUPT
Definition rfsv.h:172
@ E_PSI_FILE_DISC
Definition rfsv.h:156
@ E_PSI_FILE_CANCEL
Definition rfsv.h:154
@ E_PSI_FILE_HANDLE
Definition rfsv.h:186
@ E_PSI_FILE_NXIST
Definition rfsv.h:139
@ E_PSI_FILE_READ
Definition rfsv.h:141
@ E_PSI_FILE_RECORD
Definition rfsv.h:149
@ E_PSI_FILE_NOTREADY
Definition rfsv.h:168
@ E_PSI_FILE_LINE
Definition rfsv.h:159
@ E_PSI_FILE_OVERRUN
Definition rfsv.h:163
@ E_PSI_FILE_PARITY
Definition rfsv.h:161
@ E_PSI_FILE_INV
Definition rfsv.h:151
@ E_PSI_FILE_FRAME
Definition rfsv.h:162
@ E_PSI_FILE_NAME
Definition rfsv.h:144
@ E_PSI_GEN_NONE
Definition rfsv.h:114
@ E_PSI_FILE_ABORT
Definition rfsv.h:173
@ E_PSI_FILE_LOCKED
Definition rfsv.h:146
@ E_PSI_FILE_PROTECT
Definition rfsv.h:171
@ E_PSI_FILE_DIRFULL
Definition rfsv.h:170
@ E_PSI_FILE_COMPLETION
Definition rfsv.h:182
@ E_PSI_FILE_DRIVER
Definition rfsv.h:181
@ E_PSI_FILE_INVALID
Definition rfsv.h:175
@ E_PSI_FILE_EOF
Definition rfsv.h:142
@ E_PSI_FILE_UNKNOWN
Definition rfsv.h:169
A factory for automatically instantiating the correct protocol variant depending on the connected Psi...
Definition rpcsfactory.h:33
RPCS * create(bool, Enum< ConnectionError > *error=nullptr)
Creates a new RPCS instance.
Remote procedure call services via PLP.
Definition rpcs.h:52
void debuglog(const char *fmt,...)
Definition fuse.c:51
struct fuse_operations plp_oper
Definition fuse.c:640
int debug
Definition fuse.c:48
bool parse_port(const std::string &arg, std::string *host, int *port)
Definition cliutils.cc:53
int lookup_default_port()
Definition cliutils.cc:44
Definition doctest.h:522
int rfsv_rmdir(const char *name)
Definition main.cc:187
int rfsv_dir(const char *file, dentry **e)
Definition main.cc:157
static BufferStore owner
Definition main.cc:65
int rfsv_drivelist(int *cnt, device **dlist)
Definition main.cc:311
int epocerr_to_errno(long epocerr)
Definition main.cc:69
int rfsv_open(const char *name, long mode, uint32_t *handle)
Definition main.cc:222
int rfsv_mkdir(const char *file)
Definition main.cc:193
int rfsv_getattr(const char *name, long *attr, long *size, long *time)
Definition main.cc:292
int main(int argc, char **argv)
Definition main.cc:404
int rfsv_dircount(const char *file, uint32_t *count)
Definition main.cc:181
int rfsv_remove(const char *file)
Definition main.cc:199
static struct option opts[]
Definition main.cc:359
static RFSVFactory * rf
Definition main.cc:61
int rfsv_setmtime(const char *name, long time)
Definition main.cc:266
int rfsv_write(const char *buf, long offset, long len, const char *name)
Definition main.cc:251
int rfsv_fcreate(long attr, const char *file, uint32_t *handle)
Definition main.cc:211
int rfsv_setattr(const char *name, long sattr, long dattr)
Definition main.cc:286
static RPCS * r
Definition main.cc:63
int rfsv_fclose(long handle)
Definition main.cc:205
static void help()
Definition main.cc:343
static RFSV * a
Definition main.cc:60
int rfsv_rename(const char *oldname, const char *newname)
Definition main.cc:305
static RPCSFactory * rp
Definition main.cc:64
int rfsv_isalive(void)
Definition main.cc:149
int rfsv_setsize(const char *name, long size)
Definition main.cc:272
int fuse(int argc, char *argv[])
Definition main.cc:367
int rfsv_read(char *buf, long offset, long len, const char *name)
Definition main.cc:236
#define _(String)
Definition plpintl.h:34
std::deque< class PlpDirent > PlpDir
Definition rfsv.h:34
long time
Definition plpfuse.h:53
char * name
Definition plpfuse.h:39
struct p_device * next
Definition plpfuse.h:44