Skip to content
This repository
Browse code

Merge pull request #35 from mtheall/master

ftpd
  • Loading branch information...
commit b03a976174219ded2823719babb91e07a06a5d1b 2 parents 262991a + d962aeb
fincs authored May 15, 2012
11  apps/unixtools/README.md
Source Rendered
@@ -40,6 +40,17 @@ Usage:
40 40
     cp <SOURCE FILE>... <TARGET DIRECTORY>
41 41
     cp <SOURCE FILE> <TARGET FILE>
42 42
 
  43
+ftpd
  44
+----
  45
+
  46
+FTP Server
  47
+
  48
+Usage:
  49
+
  50
+    ftpd
  51
+
  52
+Connect with a standard FTP client. If you get a message "Not enough space", you may need to wait up to five minutes due to dswifi limitations.
  53
+
43 54
 host
44 55
 ----
45 56
 
40  apps/unixtools/ftpd/Makefile
... ...
@@ -0,0 +1,40 @@
  1
+#---------------------------------------------------------------------------------
  2
+.SUFFIXES:
  3
+#---------------------------------------------------------------------------------
  4
+
  5
+ifeq ($(strip $(DEVKITPRO)),)
  6
+$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>devkitPro")
  7
+endif
  8
+
  9
+ifeq ($(strip $(DEVKITARM)),)
  10
+$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
  11
+endif
  12
+
  13
+ifeq ($(strip $(FEOSSDK)),)
  14
+$(error "Please set FEOSSDK in your environment. export FEOSSDK=<path to>FeOS/sdk")
  15
+endif
  16
+
  17
+FEOSMK = $(FEOSSDK)/mk
  18
+
  19
+#---------------------------------------------------------------------------------
  20
+# TARGET is the name of the output
  21
+# BUILD is the directory where object files & intermediate files will be placed
  22
+# SOURCES is a list of directories containing source code
  23
+# DATA is a list of directories containing data files
  24
+# INCLUDES is a list of directories containing header files
  25
+#---------------------------------------------------------------------------------
  26
+TARGET        := $(shell basename $(CURDIR))
  27
+BUILD         := build
  28
+SOURCES       := source
  29
+DATA          := data
  30
+INCLUDES      := include
  31
+
  32
+CONF_USERLIBS := feoswifi
  33
+CONF_LIBS := -lfeoswifi
  34
+CONF_DEFINES =
  35
+
  36
+include $(FEOSMK)/app.mk
  37
+
  38
+install: all
  39
+	@cp $(TARGET).fx2 $(FEOSDEST)/data/FeOS/bin/$(TARGET).fx2 || exit 1
  40
+
832  apps/unixtools/ftpd/source/main.c
... ...
@@ -0,0 +1,832 @@
  1
+#include <arpa/inet.h>
  2
+#include <ctype.h>
  3
+#include <dirent.h>
  4
+#include <errno.h>
  5
+#include <netdb.h>
  6
+#include <netinet/in.h>
  7
+#include <stdio.h>
  8
+#include <stdlib.h>
  9
+#include <string.h>
  10
+#include <sys/socket.h>
  11
+#include <sys/stat.h>
  12
+#include <sys/types.h>
  13
+#include <unistd.h>
  14
+
  15
+#ifdef FEOS
  16
+  #include <feos.h>
  17
+  #include <dswifi9.h>
  18
+  typedef int socklen_t;
  19
+  #define perror(x) fprintf(stderr, x ": %s\n", strerror(errno))
  20
+  #define INET_ADDRSTRLEN 16
  21
+  #define PATH_MAX 1024
  22
+#else
  23
+  #include <sys/ioctl.h>
  24
+  static inline void closesocket(int s) { close(s); }
  25
+  #define swiWaitForVBlank() usleep(16666)
  26
+#endif
  27
+
  28
+#ifdef DEBUG
  29
+#define debug(x ...) printf(x)
  30
+#define closesocket(x) do { debug("closed %d\n", x); closesocket(x); } while(0);
  31
+#else
  32
+#define debug(x ...) ((void)0)
  33
+#endif
  34
+
  35
+static char buf[1024];      // general-purpose buffer
  36
+static char path[PATH_MAX]; // buffer for storing paths
  37
+struct sockaddr_in taddr;   // data transfer address
  38
+int data = -1;              // data transfer socket
  39
+
  40
+#define FUNC(x) void x(int, fd_set*)
  41
+FUNC(CDUP);        // change to parent directory
  42
+FUNC(CWD);         // change working directory
  43
+FUNC(LIST);        // list directory
  44
+FUNC(NOOP);        // no-op
  45
+FUNC(PASS);        // password
  46
+FUNC(PORT);        // address for data transfer
  47
+FUNC(PWD);         // print working directory
  48
+FUNC(QUIT);        // quit
  49
+FUNC(RETR);        // retrieve file
  50
+FUNC(STOR);        // store file
  51
+FUNC(STRU);        // file structure
  52
+FUNC(SYST);        // system
  53
+FUNC(TYPE);        // data transfer type
  54
+FUNC(USER);        // user name
  55
+FUNC(UNSUPPORTED); // command is unsupported
  56
+
  57
+typedef struct {
  58
+  const char *cmd;
  59
+  void (*func)(int sock, fd_set *master);
  60
+} ftp_cmd_t;
  61
+
  62
+ftp_cmd_t commands[] = {
  63
+#define CMD(x) { #x, x, }
  64
+  CMD(CDUP),
  65
+  CMD(CWD),
  66
+  CMD(LIST),
  67
+  CMD(NOOP),
  68
+  CMD(PASS),
  69
+  CMD(PORT),
  70
+  CMD(PWD),
  71
+  CMD(QUIT),
  72
+  CMD(RETR),
  73
+  CMD(STOR),
  74
+  CMD(STRU),
  75
+  CMD(SYST),
  76
+  CMD(TYPE),
  77
+  CMD(USER),
  78
+};
  79
+#define NUM_CMDS (sizeof(commands)/sizeof(commands[0]))
  80
+
  81
+/* send data over a socket
  82
+ * handles partial intermediate send()'s and handles non-blocking sockets
  83
+ */
  84
+static inline int Send(int sock, const char *buf, int len) {
  85
+  int sent = 0;
  86
+  int toSend;
  87
+  int rc;
  88
+
  89
+  while(sent < len) {
  90
+    if(len - sent > 1024)
  91
+      toSend = 1024;
  92
+    else
  93
+      toSend = len - sent;
  94
+
  95
+    rc = send(sock, &buf[sent], toSend, 0);
  96
+    if(rc > 0)
  97
+      sent += rc;
  98
+    else if(rc == -1 && errno == EWOULDBLOCK)
  99
+      swiWaitForVBlank();
  100
+    else
  101
+      return rc;
  102
+  }
  103
+
  104
+  return sent;
  105
+}
  106
+
  107
+/* receive data over a socket
  108
+ * handles partial intermediate recv()'s and handles non-blocking sockets
  109
+ */
  110
+static inline int Recv(int sock, char *buf, int len) {
  111
+  int rect = 0;
  112
+  int toRecv;
  113
+  int rc;
  114
+
  115
+  while(rect < len) {
  116
+    if(len - rect > 1024)
  117
+      toRecv = 1024;
  118
+    else
  119
+      toRecv = len - rect;
  120
+
  121
+    rc = recv(sock, &buf[rect], toRecv, 0);
  122
+    if(rc > 0)
  123
+      rect += rc;
  124
+    else if(rc == -1 && errno == EWOULDBLOCK)
  125
+      swiWaitForVBlank();
  126
+    else
  127
+      return rc;
  128
+  }
  129
+
  130
+  return rect;
  131
+}
  132
+
  133
+int main(int argc, char *argv[]) {
  134
+  // ioctl/setsockopt values
  135
+  int    yes = 1;
  136
+  int    no  = 0;
  137
+
  138
+  int    rc;       // return code
  139
+  int    listener; // listening socket
  140
+  char   *msg;     // message to send
  141
+
  142
+  struct sockaddr_in addr;    // address for binding/accepting
  143
+  socklen_t          addrlen; // length of address
  144
+
  145
+  // data for select()
  146
+  struct timeval t;
  147
+  fd_set master, slave;
  148
+  int    maxfd;
  149
+
  150
+#ifdef FEOS
  151
+  // initialize WiFi
  152
+  if(!Wifi_Startup()) {
  153
+    fprintf(stderr, "Wifi Failed to initialize\n");
  154
+    return 1;
  155
+  }
  156
+  debug("Initialized Wifi\n");
  157
+#endif
  158
+
  159
+  // allocate socket for listener
  160
+  listener = socket(AF_INET, SOCK_STREAM, 0);
  161
+  if(listener == -1) {
  162
+    perror("socket");
  163
+    return 1;
  164
+  }
  165
+  debug("Created socket (listener = %d)\n", listener);
  166
+
  167
+  // allow address to be reused (no effect on NDS)
  168
+  rc = setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
  169
+  if(rc == -1) {
  170
+    perror("setsockopt");
  171
+    closesocket(listener);
  172
+    return 1;
  173
+  }
  174
+
  175
+  // set up address for binding
  176
+  addr.sin_family = AF_INET;
  177
+  addr.sin_port   = htons(21);
  178
+  addr.sin_addr.s_addr = INADDR_ANY;
  179
+
  180
+  // bind address
  181
+  rc = bind(listener, (struct sockaddr*)&addr, sizeof(addr));
  182
+  if(rc == -1) {
  183
+    perror("bind");
  184
+    closesocket(listener);
  185
+    return 1;
  186
+  }
  187
+  debug("Bound socket to port %d\n", ntohs(addr.sin_port));
  188
+
  189
+  // set listener to non-blocking
  190
+  rc = ioctl(listener, FIONBIO, (char*)&yes);
  191
+  if(rc == -1) {
  192
+    perror("ioctl");
  193
+    closesocket(listener);
  194
+    return 1;
  195
+  }
  196
+  debug("Set listener to non-blocking\n");
  197
+
  198
+  // make listener listen
  199
+  rc = listen(listener, 5);
  200
+  if(rc == -1) {
  201
+    perror("listen");
  202
+    closesocket(listener);
  203
+    return 1;
  204
+  }
  205
+  debug("Set listener to listen\n");
  206
+
  207
+  // initialize the fd set
  208
+  FD_ZERO(&master);
  209
+  FD_SET(listener, &master);
  210
+  maxfd = listener;
  211
+
  212
+  // wait for activity
  213
+  while(1) {
  214
+    // check if somebody is connect()'ing. need this check because
  215
+    // select() doesn't work on listening sockets on NDS
  216
+    addrlen = sizeof(addr);
  217
+    rc = accept(listener, (struct sockaddr*)&addr, &addrlen);
  218
+    if(rc == -1) {
  219
+      if(errno != EWOULDBLOCK)
  220
+        perror("accept");
  221
+    }
  222
+    // add connection to fd set
  223
+    else {
  224
+      debug("accepted socket %d\n", rc);
  225
+      FD_SET(rc, &master);
  226
+
  227
+      // accept()'ed socket inherits non-blocking
  228
+      // set it to blocking
  229
+      if(ioctl(rc, FIONBIO, (char*)&no) == -1) {
  230
+        perror("ioctl");
  231
+        closesocket(rc);
  232
+        FD_CLR(rc, &master);
  233
+        rc = -1;
  234
+      }
  235
+      else
  236
+        debug("set %d to blocking\n", rc);
  237
+
  238
+      // update the maxfd
  239
+      if(rc > maxfd)
  240
+        maxfd = rc;
  241
+    }
  242
+ 
  243
+    // reinitialize the fd set and timeout
  244
+    memcpy(&slave, &master, sizeof(fd_set));
  245
+    t.tv_sec  = 1;
  246
+    t.tv_usec = 0;
  247
+
  248
+    // check activity on the sockets
  249
+    rc = select(maxfd+1, &slave, NULL, NULL, &t);
  250
+    if(rc == -1)
  251
+      perror("select");
  252
+
  253
+    // there was some activity
  254
+    else if(rc > 0) {
  255
+      int i;
  256
+
  257
+      // see what was active
  258
+      for(i = 0; i < maxfd+1; i++) {
  259
+        if(FD_ISSET(i, &slave)) {
  260
+          // the listener had activity. accept() the connection
  261
+          if(i == listener) {
  262
+            addrlen = sizeof(addr);
  263
+            rc = accept(i, (struct sockaddr*)&addr, &addrlen);
  264
+
  265
+            if(rc == -1)
  266
+              perror("accept");
  267
+            else {
  268
+              int sock = rc;
  269
+
  270
+              // update the maxfd
  271
+              if(sock > maxfd)
  272
+                maxfd = sock;
  273
+
  274
+              // add to the fd set
  275
+              FD_SET(sock, &master);
  276
+              debug("accepted socket %d\n", rc);
  277
+
  278
+              // send the welcome message
  279
+              debug("Sending welcome message\n");
  280
+              msg = "220 Welcome to FeOS\r\n";
  281
+              rc = Send(sock, msg, strlen(msg));
  282
+              if(rc == -1) {
  283
+                perror("send");
  284
+                FD_CLR(sock, &master);
  285
+                closesocket(sock);
  286
+              }
  287
+            }
  288
+          }
  289
+
  290
+          // this was not the listener
  291
+          else {
  292
+            // read in the activity
  293
+            memset(buf, 0, sizeof(buf));
  294
+            rc = recv(i, buf, sizeof(buf), 0);
  295
+
  296
+            if(rc == -1)
  297
+              perror("recv");
  298
+            else if(rc == 0) {
  299
+              debug("%d disconnected\n", i);
  300
+              FD_CLR(i, &master);
  301
+              closesocket(i);
  302
+            }
  303
+            else {
  304
+              int j;
  305
+
  306
+              // print out what we got
  307
+              debug("%*s", rc, buf);
  308
+
  309
+              // lookup the command and execute it
  310
+              for(j = 0; j < NUM_CMDS; j++) {
  311
+                if(strncmp(buf, commands[j].cmd, strlen(commands[j].cmd)) == 0) {
  312
+                  commands[j].func(i, &master);
  313
+                  break;
  314
+                }
  315
+              }
  316
+              // the command did not exist
  317
+              if(j == NUM_CMDS)
  318
+                UNSUPPORTED(i, &master);
  319
+            }
  320
+          }
  321
+        }
  322
+      }
  323
+    }
  324
+    // wait a small amount of time to prevent lockups
  325
+    swiWaitForVBlank();
  326
+  }
  327
+
  328
+#ifdef FEOS
  329
+  // deinitialize WiFi
  330
+  Wifi_Cleanup();
  331
+#endif
  332
+
  333
+  return 0;
  334
+}
  335
+
  336
+// macro to kill control connection in the event of failure
  337
+#define SEND() \
  338
+do { \
  339
+  rc = Send(sock, msg, strlen(msg)); \
  340
+  if(rc == -1) { \
  341
+    perror("send"); \
  342
+    FD_CLR(sock, master); \
  343
+    closesocket(sock); \
  344
+    return; \
  345
+  } \
  346
+} while(0)
  347
+
  348
+// destroy the data connection
  349
+static inline void putDataConnection() {
  350
+  closesocket(data);
  351
+  data = -1;
  352
+}
  353
+
  354
+// create a data connection
  355
+static inline void getDataConnection(int sock, fd_set *master) {
  356
+  int rc;
  357
+  const char *msg;
  358
+
  359
+  // a data connection does not exist
  360
+  if(data == -1) {
  361
+    // send message to indicate pending connection
  362
+    msg = "150 Opening data connection\r\n";
  363
+    SEND();
  364
+
  365
+    // create a socket for the data connection
  366
+    data = socket(AF_INET, SOCK_STREAM, 0);
  367
+    if(data == -1) {
  368
+      memset(buf, 0, sizeof(buf));
  369
+      sprintf(buf, "425 %s\r\n", strerror(errno));
  370
+      msg = buf;
  371
+      SEND();
  372
+      return;
  373
+    }
  374
+    debug("created socket %d\n", data);
  375
+
  376
+    // connect to the address specified earlier
  377
+    rc = connect(data, (struct sockaddr*)&taddr, sizeof(taddr));
  378
+    if(rc == -1) {
  379
+      perror("socket");
  380
+      putDataConnection();
  381
+      memset(buf, 0, sizeof(buf));
  382
+      sprintf(buf, "425 %s\r\n", strerror(errno));
  383
+      msg = buf;
  384
+      SEND();
  385
+      return;
  386
+    }
  387
+    debug("connected\n");
  388
+  }
  389
+}
  390
+
  391
+void UNSUPPORTED(int sock, fd_set *master) {
  392
+  int rc;
  393
+  const char *msg = "202 Command not implemented\r\n";
  394
+
  395
+  SEND();
  396
+}
  397
+
  398
+// allow public access
  399
+void USER(int sock, fd_set *master) {
  400
+  int rc;
  401
+  const char *msg = "230 Anonymous access is allowed\r\n";
  402
+
  403
+  SEND();
  404
+}
  405
+
  406
+// unused due to universal public access
  407
+void PASS(int sock, fd_set *master) {
  408
+  int rc;
  409
+  const char *msg = "202 No password necessary\r\n";
  410
+
  411
+  SEND();
  412
+}
  413
+
  414
+// generic response
  415
+void SYST(int sock, fd_set *master) {
  416
+  int rc;
  417
+  const char *msg = "215 UNIX Type: L8\r\n";
  418
+
  419
+  SEND();
  420
+}
  421
+
  422
+void PORT(int sock, fd_set *master) {
  423
+  int rc;
  424
+  const char *msg;
  425
+  char address[INET_ADDRSTRLEN];
  426
+  int a1, a2, a3, a4, p1, p2;
  427
+
  428
+  // scan the parameters
  429
+  if(sscanf(buf, "PORT %d,%d,%d,%d,%d,%d", &a1, &a2, &a3, &a4, &p1, &p2) != 6) {
  430
+    msg = "501 Parameter syntax error\r\n";
  431
+    SEND();
  432
+    return;
  433
+  }
  434
+
  435
+  // reassemble into dot-syntax
  436
+  sprintf(address, "%d.%d.%d.%d", a1, a2, a3, a4);
  437
+
  438
+  // initialize the data address
  439
+  taddr.sin_family = AF_INET;
  440
+  taddr.sin_port   = htons(p1*256+p2);
  441
+  taddr.sin_addr.s_addr = inet_addr(address);
  442
+
  443
+  msg = "200 OK\r\n";
  444
+  SEND();
  445
+}
  446
+
  447
+void LIST(int sock, fd_set *master) {
  448
+  int rc;
  449
+  const char *msg;
  450
+
  451
+  struct stat statbuf;
  452
+  DIR *dp;
  453
+  struct dirent *dent;
  454
+
  455
+  // scan the parameter
  456
+  if(sscanf(buf, "LIST %s", path) != 1)
  457
+    strcpy(path, "."); // no parameter; use current working directory
  458
+
  459
+  // attempt to list a directory
  460
+  dp = opendir(path);
  461
+  if(dp == NULL) { // it is not a directory
  462
+    // attempt to list a file
  463
+    if(stat(path, &statbuf) == -1) {
  464
+      memset(buf, 0, sizeof(buf));
  465
+      sprintf(buf, "450 %s\r\n", strerror(errno));
  466
+      msg = buf;
  467
+      SEND();
  468
+      return;
  469
+    }
  470
+
  471
+    getDataConnection(sock, master);
  472
+    if(data == -1)
  473
+      return;
  474
+
  475
+    // this is a file
  476
+    memset(buf, 0, sizeof(buf));
  477
+    sprintf(buf, "+r\t%s\r\n", path);
  478
+
  479
+    // send the data
  480
+    rc = Send(data, buf, strlen(buf));
  481
+    swiWaitForVBlank();
  482
+    if(rc == -1) {
  483
+      putDataConnection();
  484
+      memset(buf, 0, sizeof(buf));
  485
+      sprintf(buf, "426 %s\r\n", strerror(errno));
  486
+      msg = buf;
  487
+      SEND();
  488
+      return;
  489
+    }
  490
+
  491
+    // terminate the data connection
  492
+    putDataConnection();
  493
+    msg = "226 File list complete\r\n";
  494
+    SEND();
  495
+    return;
  496
+  }
  497
+
  498
+  getDataConnection(sock, master);
  499
+  if(data == -1) {
  500
+    closedir(dp);
  501
+    return;
  502
+  }
  503
+
  504
+  // it was a directory; list its contents
  505
+  while((dent = readdir(dp))) {
  506
+    memset(buf, 0, sizeof(buf));
  507
+
  508
+    // filter . and ..
  509
+    if(strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0)
  510
+      continue;
  511
+
  512
+    // this is a directory
  513
+    if(dent->d_type == DT_DIR)
  514
+      sprintf(buf, "+/\t%s\r\n", dent->d_name);
  515
+
  516
+    // this is a file
  517
+    else if(dent->d_type == DT_REG)
  518
+      sprintf(buf, "+r\t%s\r\n", dent->d_name);
  519
+
  520
+    // filter out everything else
  521
+    else
  522
+      continue;
  523
+
  524
+    // send the entry
  525
+    rc = Send(data, buf, strlen(buf));
  526
+    swiWaitForVBlank();
  527
+    if(rc == -1) {
  528
+      putDataConnection();
  529
+      closedir(dp);
  530
+      memset(buf, 0, sizeof(buf));
  531
+      sprintf(buf, "426 %s\r\n", strerror(errno));
  532
+      msg = buf;
  533
+      SEND();
  534
+      return;
  535
+    }
  536
+  }
  537
+
  538
+  // finished
  539
+  closedir(dp);
  540
+  putDataConnection();
  541
+
  542
+  msg = "226 Directory listing complete\r\n";
  543
+  SEND();
  544
+}
  545
+
  546
+void RETR(int sock, fd_set *master) {
  547
+  int rc;
  548
+  const char *msg;
  549
+  FILE *fp;
  550
+
  551
+  // scan the parameter
  552
+  if(sscanf(buf, "RETR %s", path) != 1) {
  553
+    msg = "501 Parameter syntax error\r\n";
  554
+    SEND();
  555
+    return;
  556
+  }
  557
+
  558
+  // open the file
  559
+  fp = fopen(path, "rb");
  560
+  if(fp == NULL) {
  561
+    memset(buf, 0, sizeof(buf));
  562
+    sprintf(buf, "425 %s\r\n", strerror(errno));
  563
+    msg = buf;
  564
+    SEND();
  565
+    return;
  566
+  }
  567
+
  568
+  memset(buf, 0, sizeof(buf));
  569
+  getDataConnection(sock, master);
  570
+  if(data == -1)
  571
+    return;
  572
+
  573
+  do {
  574
+    // read data from the file
  575
+    rc = fread(buf, 1, sizeof(buf), fp);
  576
+    if(rc == -1 && !feof(fp)) {
  577
+      perror("fread");
  578
+      fclose(fp);
  579
+      putDataConnection();
  580
+      msg = "426 Connection closed; transfer aborted\r\n";
  581
+      SEND();
  582
+      return;
  583
+    }
  584
+    // send the data
  585
+    else if(rc > 0) {
  586
+      rc = Send(data, buf, rc);
  587
+      swiWaitForVBlank();
  588
+      if(rc == -1) {
  589
+        perror("send");
  590
+        fclose(fp);
  591
+        putDataConnection();
  592
+        msg = "426 Connection closed; transfer aborted\r\n";
  593
+        SEND();
  594
+        return;
  595
+      }
  596
+    }
  597
+
  598
+    // end of file. terminate the data connection
  599
+    if(feof(fp)) {
  600
+      fclose(fp);
  601
+      putDataConnection();
  602
+      msg = "226 Transfer complete\r\n";
  603
+      SEND();
  604
+      return;
  605
+    }
  606
+  } while(rc > 0);
  607
+}
  608
+
  609
+void STOR(int sock, fd_set *master) {
  610
+  int rc;
  611
+  const char *msg;
  612
+  FILE *fp;
  613
+
  614
+  // scan the parameter
  615
+  if(sscanf(buf, "STOR %s", path) != 1) {
  616
+    msg = "501 Parameter syntax error\r\n";
  617
+    SEND();
  618
+    return;
  619
+  }
  620
+
  621
+  // open the file
  622
+  fp = fopen(path, "wb");
  623
+  if(fp == NULL) {
  624
+    memset(buf, 0, sizeof(buf));
  625
+    sprintf(buf, "425 %s\r\n", strerror(errno));
  626
+    msg = buf;
  627
+    SEND();
  628
+    return;
  629
+  }
  630
+
  631
+  getDataConnection(sock, master);
  632
+  if(data == -1)
  633
+    return;
  634
+
  635
+  do {
  636
+    // read data from the data connection
  637
+    memset(buf, 0, sizeof(buf));
  638
+    rc = recv(data, buf, sizeof(buf), 0);
  639
+    swiWaitForVBlank();
  640
+    if(rc == -1) {
  641
+      perror("recv");
  642
+      fclose(fp);
  643
+      putDataConnection();
  644
+      msg = "426 Connection closed; transfer aborted\r\n";
  645
+      SEND();
  646
+      return;
  647
+    }
  648
+    // connection was closed. assume end of transmission
  649
+    else if(rc == 0) {
  650
+      putDataConnection();
  651
+      fclose(fp);
  652
+
  653
+      msg = "226 Transfer complete\r\n";
  654
+      SEND();
  655
+      return;
  656
+    }
  657
+
  658
+    // write data to the file
  659
+    if(fwrite(buf, rc, 1, fp) != 1) {
  660
+      perror("fwrite");
  661
+      fclose(fp);
  662
+      putDataConnection();
  663
+      msg = "426 Connection closed; transfer aborted\r\n";
  664
+      SEND();
  665
+      return;
  666
+    }
  667
+  } while(rc > 0);
  668
+}
  669
+
  670
+// user exited
  671
+void QUIT(int sock, fd_set *master) {
  672
+  int rc;
  673
+  const char *msg = "221 Thank you for visiting FeOS\r\n";
  674
+
  675
+  SEND();
  676
+
  677
+  // remove from the fd set
  678
+  FD_CLR(sock, master);
  679
+  closesocket(sock);
  680
+}
  681
+
  682
+void TYPE(int sock, fd_set *master) {
  683
+  int rc;
  684
+  const char *msg;
  685
+  char c[2];
  686
+
  687
+  // scan the parameters
  688
+  rc = sscanf(buf, "TYPE %c %c", &c[0], &c[1]);
  689
+  if(rc != 1 && rc != 2) {
  690
+    msg = "501 Parameter syntax error\r\n";
  691
+    SEND();
  692
+    return;
  693
+  }
  694
+
  695
+  // translate to uppercase
  696
+  c[0] = toupper(c[0]);
  697
+  if(rc == 2)
  698
+    c[1] = toupper(c[1]);
  699
+
  700
+  // check the parameter values
  701
+  if(c[0] != 'A' && c[0] != 'E' && c[0] != 'I' && c[0] != 'L') {
  702
+    msg = "501 Invalid parameter\r\n";
  703
+    SEND();
  704
+    return;
  705
+  }
  706
+  if(rc == 2 && c[1] != 'N' && c[1] != 'T' && c[1] != 'C') {
  707
+    msg = "501 Invalid parameter\r\n";
  708
+    SEND();
  709
+    return;
  710
+  }
  711
+  if((c[0] != 'A' && c[0] != 'I') || (rc == 2 && c[1] != 'N')) {
  712
+    memset(buf, 0, sizeof(buf));
  713
+    sprintf(buf, "504 rc = %d c[0] = %c\r\n", rc, c[0]);
  714
+    msg = "504 Command not implemented for that parameter\r\n";
  715
+    msg = buf;
  716
+    SEND();
  717
+    return;
  718
+  }
  719
+
  720
+  // this is really a no-op because we don't distinguish between
  721
+  // binary and ascii
  722
+  msg = "200 OK\r\n";
  723
+  SEND();
  724
+}
  725
+
  726
+void PWD(int sock, fd_set *master) {
  727
+  int rc;
  728
+  const char *msg;
  729
+  static char mybuf[PATH_MAX+10];
  730
+
  731
+  // get the current working directory
  732
+  memset(path, 0, sizeof(path));
  733
+  if(getcwd(path, sizeof(path)) == NULL) {
  734
+    memset(buf, 0, sizeof(buf));
  735
+    sprintf(buf, "550 %s\r\n", strerror(errno));
  736
+    msg = buf;
  737
+    SEND();
  738
+    return;
  739
+  }
  740
+
  741
+  // skip over the device specifier (fat: sd: etc)
  742
+  msg = path;
  743
+  while(msg < &path[sizeof(path)] && *msg != '/')
  744
+    msg++;
  745
+
  746
+  // send over the path
  747
+  sprintf(mybuf, "257 \"%s\"\r\n", msg);
  748
+  msg = mybuf;
  749
+  SEND();
  750
+}
  751
+
  752
+void CWD(int sock, fd_set *master) {
  753
+  int rc;
  754
+  const char *msg;
  755
+
  756
+  // scan parameter
  757
+  if(sscanf(buf, "CWD %s", path) != 1) {
  758
+    msg = "501 Parameter syntax error\r\n";
  759
+    SEND();
  760
+    return;
  761
+  }
  762
+
  763
+  // change to new directory
  764
+  if(chdir(path) == -1) {
  765
+    memset(buf, 0, sizeof(buf));
  766
+    sprintf(buf, "550 %s\r\n", strerror(errno));
  767
+    msg = buf;
  768
+    SEND();
  769
+    return;
  770
+  }
  771
+
  772
+  memset(buf, 0, sizeof(buf));
  773
+  sprintf(buf, "250 Changed to '%s'\r\n", path);
  774
+  msg = buf;
  775
+  SEND();
  776
+}
  777
+
  778
+void CDUP(int sock, fd_set *master) {
  779
+  int rc;
  780
+  const char *msg;
  781
+
  782
+  // change to parent directory
  783
+  if(chdir("..") == -1) {
  784
+    memset(buf, 0, sizeof(buf));
  785
+    sprintf(buf, "550 %s\r\n", strerror(errno));
  786
+    msg = buf;
  787
+    SEND();
  788
+    return;
  789
+  }
  790
+
  791
+  msg = "200 OK\r\n";
  792
+  SEND();
  793
+}
  794
+
  795
+void NOOP(int sock, fd_set *master) {
  796
+  int rc;
  797
+  const char *msg;
  798
+
  799
+  msg = "200 OK\r\n";
  800
+  SEND();
  801
+}
  802
+
  803
+void STRU(int sock, fd_set *master) {
  804
+  int rc;
  805
+  const char *msg;
  806
+  char c;
  807
+
  808
+  // scan the parameter
  809
+  if(sscanf(buf, "STRU %c", &c) != 1) {
  810
+    msg = "501 Parameter syntax error\r\n";
  811
+    SEND();
  812
+    return;
  813
+  }
  814
+
  815
+  // we support File structure
  816
+  if(c == 'f' || c == 'F') {
  817
+    msg = "200 OK\r\n";
  818
+    SEND();
  819
+    return;
  820
+  }
  821
+  // we do not support Record and Page structures
  822
+  else if(c == 'r' || c == 'R' || c == 'p' || c == 'P') {
  823
+    msg = "504 Command not implemented for that parameter\r\n";
  824
+    SEND();
  825
+    return;
  826
+  }
  827
+
  828
+  // all others are invalid
  829
+  msg = "501 Invalid parameter\r\n";
  830
+  SEND();
  831
+}
  832
+

0 notes on commit b03a976

Please sign in to comment.
Something went wrong with that request. Please try again.