/[mit-cadr]/branches/ggilley/emulator/usim/Files.c
ViewVC logotype

Contents of /branches/ggilley/emulator/usim/Files.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 410 - (show annotations)
Sun Mar 3 22:44:10 2013 UTC (13 months, 1 week ago) by ggilley
File MIME type: text/plain
File size: 157235 byte(s)
fix an error and some warnings
1 /*
2 * chaosnet FILE protocol server
3 *
4 * Adapted from MIT UNIX chaosnet code
5 *
6 * modified to be used from userland chaos server instead of via kernel
7 * chaos sockets. a bit of a hack, but it does work.
8 *
9 * 10/2004 brad@heeltoe.com
10 * byte order cleanups; Joseph Oswald <josephoswald@gmail.com>
11 */
12
13 /* NOTES
14 * 7/5/84 -Cory Myers
15 * changed creat mode to 0644 - no group or other write from 0666
16 * fixed filepos to adjust for bytesize
17 *
18 * 9/11/84 dove
19 * finger users to console
20 *
21 * 9/20/84 Cory Myers
22 * Login users must have passwords
23 *
24 * 1/30/85 dove
25 * use initgroups() not setgid() in BSD42
26 *
27 * 4/29/85 Cory Myers
28 * allow logins without passwords from privileged hosts
29 *
30 * 8/23/85 dove (was FILE.c4)
31 * finger users to logger (a.k.a. syslog) instead of to console
32 *
33 * 3/08/88 Greg Troxel
34 * ifdef out cory's code of 4/29/85 for privileged hosts
35 * Conditional on PRIVHOSTS
36 */
37
38 #include <stdio.h>
39 #include <ctype.h>
40 #include <fcntl.h>
41 #include <sys/param.h>
42 #include <sys/stat.h>
43 #include <sys/ioctl.h>
44 #include <sys/timeb.h>
45 #include <sys/socket.h>
46
47 #if defined(OSX)
48 #import <dispatch/dispatch.h>
49 #endif
50
51 #include <time.h>
52 #include <sys/dir.h>
53
54 #include <string.h>
55 #define BSIZE 512
56 #define SBLOCK 8
57 #define FSBSIZE BSIZE
58
59 #ifndef MIN
60 #define MIN(a,b) ((a) < (b) ? (a) : (b))
61 #endif
62
63 #define _XOPEN_SOURCE
64 #include <unistd.h>
65 #include <stdlib.h>
66 #include <stdarg.h>
67
68 #include <errno.h>
69 #include <pwd.h>
70 #include <setjmp.h>
71 #include <signal.h>
72 #define DEFERROR
73 #include "Files.h"
74 #include "glob.h"
75 #include "chaos.h"
76
77 #ifdef linux
78 #include <sys/vfs.h>
79 #endif
80
81 #ifdef OSX
82 #include <sys/param.h>
83 #include <sys/mount.h>
84 #include <sys/time.h>
85 /* use utimes instead of "outmoded" utime */
86 #endif
87
88 #if defined(__NetBSD__) || defined(OSX) || defined(linux)
89 #include <utime.h>
90 #include <sys/statvfs.h>
91 #endif
92
93 #define TRUNCATE_DATES 0
94
95 #define CHSP (040)
96 #define CHNL (0200|015)
97 #define CHTAB (0200|011)
98 #define CHFF (0200|014)
99 #define CHBS (0200|010)
100 #define CHLF (0200|012)
101
102 /*
103 * These are the packet opcode types
104 */
105 #define RFCOP 001 /* Request for connection */
106 #define OPNOP 002 /* Open connection */
107 #define CLSOP 003 /* Close connection */
108 #define FWDOP 004 /* Forward this packet */
109 #define ANSOP 005 /* Answer packet */
110 #define SNSOP 006 /* Sense packet */
111 #define STSOP 007 /* Status packet */
112 #define RUTOP 010 /* Routing information packet */
113 #define LOSOP 011 /* Losing connection packet */
114 #define LSNOP 012 /* Listen packet (never transmitted) */
115 #define MNTOP 013 /* Maintenance packet */
116 #define EOFOP 014 /* End of File packet */
117 #define UNCOP 015 /* Uncontrolled data packet */
118 #define BRDOP 016 /* Broadcast RFC opcode */
119 #define DATOP 0200 /* Ordinary character data */
120 #define DWDOP 0300 /* 16 bit word data */
121
122
123 #define CHMAXDATA 488 /* Maximum data per packet */
124
125 struct chpacket {
126 unsigned char cp_op;
127 char cp_data[CHMAXDATA];
128 };
129
130 #define LOG_INFO 0
131 #define LOG_ERR 1
132 #define LOG_NOTICE 2
133
134 int log_verbose = 0;
135 int log_stderr_tofile = 0;
136
137 static void
138 log(int level, char *fmt, ...)
139 {
140 va_list ap;
141
142 if (log_stderr_tofile == 0) return;
143
144 va_start(ap, fmt);
145 vfprintf(stderr, fmt, ap);
146 va_end(ap);
147
148 fflush(stderr);
149 }
150
151
152 #define tell(fd) lseek(fd, (off_t)0, SEEK_CUR)
153
154 #define FILEUTMP "/tmp/chfile.utmp"
155
156 /*
157 * Chaosnet file protocol server. Written by JEK, Symbolics
158 * TODO:
159 Performance hacking.
160 More strict syntax checking in string()
161 System notifications?
162 Quoting, syntax checking
163 Subroutines for error processing?
164 Check for default match in prefix() to clean up complete().
165 Cacheing user-id's for faster directory list etc.
166 */
167
168 #define BIT(n) (1<<(n))
169 #define NOLOGIN "/etc/nologin"
170 /*
171 * Structure describing each transfer in progress.
172 * Essentially each OPEN or DIRECTORY command creates a transfer
173 * task, which runs (virtually) asynchronously with respect to the
174 * control/command main task. Certain transactions/commands
175 * are performed synchronously with the control/main process, like
176 * OPEN-PROBES, completion, etc., while others relate to the action
177 * of a transfer process (e.g. SET-BYTE-POINTER).
178 */
179 struct xfer {
180 struct xfer *x_next; /* Next in global list */
181 struct xfer *x_runq; /* Next in runnable list */
182 char x_state; /* TASK state */
183 struct file_handle *x_fh; /* File handle of process */
184 struct transaction *x_close; /* Saved close transaction */
185 long x_bytesize; /* Bytesize for binary xfers */
186 long x_options; /* OPEN options flags */
187 int x_flags; /* Randome state bits */
188 time_t x_atime; /* Access time to restore */
189 time_t x_mtime; /* Mod time to restore */
190 int x_fd; /* File descriptor of file
191 being read or written */
192 char *x_dirname; /* dirname of filename */
193 char *x_realname; /* filename */
194 char *x_tempname; /* While writing */
195 long x_left; /* Bytes in input buffer */
196 int x_room; /* Room in output buffer */
197 char *x_bptr; /* Disk buffer pointer */
198 char *x_pptr; /* Packet buffer pointer */
199 char x_bbuf[FSBSIZE]; /* Disk buffer */
200 struct chpacket x_pkt; /* Packet buffer */
201 #define x_op x_pkt.cp_op /* Packet buffer opcode */
202 #define x_pbuf x_pkt.cp_data /* Packet data buffer */
203 char **x_glob; /* Files for DIRECTORY */
204 char **x_gptr; /* Ptr into x_glob vector */
205 #if defined(OSX)
206 dispatch_semaphore_t x_hangsem;
207 #else
208 pthread_mutex_t x_hangsem;
209 pthread_cond_t x_hangcond;
210 #endif
211 pthread_mutex_t x_xfersem;
212 struct transaction *x_work; /* Queued transactions */
213 } *xfers;
214
215 #define XNULL ((struct xfer *)0)
216 /*
217 * Values for x_state.
218 */
219 #define X_PROCESS 0 /* Work is in process - everything is ok */
220 #define X_DONE 1 /* Successful completion has occurred */
221 /* Waiting to close normally */
222 /*
223 * States for the input side only.
224 */
225 #define X_BROKEN 2 /* Data connection disappeared on READ */
226 #define X_ABORT 3 /* Fatal error in reading. Awaiting CLOSE */
227 #define X_REOF 4 /* Read an EOF and sent all the data */
228 #define X_SEOF 5 /* Sent an EOF, awaiting FILEPOS or CLOSE */
229 #define X_IDLE 6 /* Waiting to start */
230 #define X_DERROR 7 /* Directory list error */
231 /*
232 * States for the output side only.
233 */
234 #define X_RSYNC 8 /* Received SYNCMARK, waiting for CLOSE */
235 #define X_WSYNC 9 /* Transfer punted or EOF, waiting for
236 SYNCMARK */
237 #define X_ERROR 10 /* Hung after recoverable error */
238 /* Waiting to continue or close abnormally */
239 #define X_RETRY 11 /* After a continue, waiting to retry the
240 recoverable operation. */
241 /*
242 * Values for x_flags
243 */
244 #define X_EOF BIT(1) /* EOF has been read from network */
245 #define X_QUOTED BIT(2) /* Used in character set translation */
246 #define X_CLOSE BIT(3) /* CLOSE command received */
247 #define X_DELETE BIT(4) /* File deleted (close is an abort) */
248 #define X_ATIME BIT(5) /* Change access time at close */
249 #define X_MTIME BIT(6) /* Change mod time at close */
250 /*
251 * Structure describing each issued command.
252 * Created by the command parser (getcmd) and extant while the command is
253 * in progress until it is done and responded to.
254 */
255 struct transaction {
256 struct transaction *t_next; /* For queuing work on xfers*/
257 char *t_tid; /* Id. for this transaction */
258 struct file_handle *t_fh; /* File handle to use */
259 struct command *t_command; /* Command to perform */
260 struct cmdargs *t_args; /* Args for this command */
261 struct chaos_packet *t_packet; /* packet that started transaction */
262 struct chaos_connection *t_connection;
263 };
264 #define TNULL ((struct transaction *) 0)
265
266 /*
267 * Structure for each possible command.
268 * Used by the parser for argument syntax and holds the actual function
269 * which performs the work.
270 */
271 struct command {
272 char *c_name; /* Command name */
273 void (*c_func)();/* Function to call */
274 int c_flags; /* Various bits. See below */
275 unsigned char *c_syntax; /* Syntax description */
276 };
277 #define CNULL ((struct command *)0)
278 /*
279 * Bit values for c_flags
280 */
281 #define C_FHMUST BIT(0) /* File handle must be present */
282 #define C_FHCANT BIT(1) /* File handle can't be present */
283 #define C_FHINPUT BIT(2) /* File handle must be for input */
284 #define C_FHOUTPUT BIT(3) /* File handle must be for output */
285 #define C_XFER BIT(4) /* Command should be queued on a transfer */
286 #define C_NOLOG BIT(5) /* Command permitted when not logged in */
287 struct plist {
288 struct plist *p_next;
289 char *p_name;
290 char *p_value;
291 };
292 #define PNULL ((struct plist *)0)
293
294 /*
295 * Structure for each "file handle", essentially one side of a
296 * bidirectional chaos "data connection".
297 */
298 struct file_handle {
299 struct file_handle *f_next; /* Next on global list */
300 char *f_name; /* Identifier from user end */
301 int f_type; /* See below */
302 int f_fd; /* UNIX file descriptor */
303 struct xfer *f_xfer; /* Active xfer on this fh */
304 struct file_handle *f_other; /* Other fh of in/out pair */
305 struct chaos_connection *f_connection;
306 } *file_handles;
307 #define FNULL ((struct file_handle *)0)
308 /*
309 * Values for f_type
310 */
311 #define F_INPUT 0 /* Input side of connection */
312 #define F_OUTPUT 1 /* Output size of connection */
313
314 /*
315 * Command options.
316 */
317 struct option {
318 char *o_name; /* Name of option */
319 char o_type; /* Type of value */
320 long o_value; /* Value of option */
321 long o_cant; /* Bit values of mutually exclusive options*/
322 };
323 /*
324 * Values for o_type
325 */
326 #define O_BIT 0 /* Value is bit to turn on in a_options */
327 #define O_NUMBER 1 /* Value is (SP, NUM) following name */
328 #define O_EXISTS 2 /* Existence checking keywords */
329
330 /*
331 * Values for o_value for O_BIT
332 */
333 #undef O_DIRECTORY
334 #define O_READ BIT(0) /* An open is for READing a file */
335 #define O_WRITE BIT(1) /* An open is for WRITEing a file */
336 #define O_PROBE BIT(2) /* An open is for PROBEing for existence */
337 #define O_CHARACTER BIT(3) /* Data will be character (lispm) */
338 #define O_BINARY BIT(4) /* Binary data */
339 #define O_RAW BIT(5) /* RAW character transfer - no translation */
340 #define O_SUPER BIT(6) /* Super-image mode */
341 #define O_TEMPORARY BIT(7) /* An open file should be temporary */
342 #define O_DELETED BIT(8) /* Include DELETED files in DIRECTORY list */
343 #define O_OLD BIT(9) /* Complete for an existing file in COMPLETE */
344 #define O_NEWOK BIT(10) /* Complete for a possible new file */
345 #define O_DEFAULT BIT(11) /* Choose character unless QFASL */
346 #define O_DIRECTORY BIT(12) /* Used internally - not a keyword option */
347 #define O_FAST BIT(13) /* Fast directory list - no properties */
348 #define O_PRESERVE BIT(14) /* Preserve reference dates - not implemented */
349 #define O_SORTED BIT(15) /* Return directory list sorted - we do this */
350 #define O_PROBEDIR BIT(16) /* Probe is for the directory, not the file */
351 #define O_PROPERTIES BIT(17) /* To distinguish PROPERTIES from DIRECTORY internally */
352 /*
353 * Values for o_value for O_NUMBER
354 */
355 #define O_BYTESIZE 0
356 #define O_ESTSIZE 1
357 #define O_MAXNUMS 2
358 /*
359 * Values for o_value for O_EXISTS
360 */
361 #define O_IFEXISTS 0
362 #define O_IFNEXISTS 1
363 #define O_MAXEXS 2
364 /*
365 * Values for O_EXISTS keywords
366 */
367 #define O_XNONE 0 /* Unspecified */
368 #define O_XNEWVERSION 1 /* Increment version before writing new file */
369 #define O_XRENAME 2 /* Rename before writing new file */
370 #define O_XRENDEL 3 /* Rename, then delete before writing new file */
371 #define O_XOVERWRITE 4 /* Smash the existing file */
372 #define O_XAPPEND 5 /* Append to existing file */
373 #define O_XSUPERSEDE 6 /* Don't clobber existing file until non-abort close */
374 #define O_XCREATE 7 /* Create file is it doesn't exists */
375 #define O_XERROR 8 /* Signal error */
376 #define O_XTRUNCATE 9 /* Truncate as well as overwrite on open */
377 /*
378 * Structure of arguments to commands.
379 */
380 #define MAXSTRINGS 3 /* Maximum # of string arguments in any cmd */
381 struct cmdargs {
382 long a_options; /* Option bits */
383 char *a_strings[MAXSTRINGS];/* Random strings */
384 char a_exists[O_MAXEXS];
385 long a_numbers[O_MAXNUMS]; /* Random numbers */
386 struct plist *a_plist; /* Property list */
387 };
388 #define ANULL ((struct cmdargs *)0)
389 /*
390 * String names for above options
391 */
392 struct xoption {
393 char *x_name;
394 long x_value;
395 long x_cant; /* Which O_EXISTS value can't occur. */
396 } xoptions[] = {
397 { "ERROR", O_XERROR, O_MAXEXS, },
398 { "NEW-VERSION", O_XNEWVERSION, O_IFNEXISTS, },
399 { "RENAME", O_XRENAME, O_IFNEXISTS, },
400 { "RENAME-AND-DELETE", O_XRENDEL, O_IFNEXISTS, },
401 { "OVERWRITE", O_XOVERWRITE, O_IFNEXISTS, },
402 { "APPEND", O_XAPPEND, O_IFNEXISTS, },
403 { "SUPERSEDE", O_XSUPERSEDE, O_IFNEXISTS, },
404 { "CREATE", O_XCREATE, O_IFEXISTS, },
405 { "TRUNCATE", O_XTRUNCATE, O_IFNEXISTS, },
406 { 0, 0, 0, },
407 };
408 /*
409 * Structure allocation macros.
410 */
411 #define salloc(s) (struct s *)malloc(sizeof(struct s))
412 #define sfree(sp) free((char *)sp)
413 #define NOSTR ((char *)0)
414 #define NOBLK ((char **)0)
415 /*
416 * Return values from dowork indicating the disposition of the transfer task.
417 */
418 #define X_FLUSH 0 /* Flush the transfer, its all over */
419 #define X_CONTINUE 1 /* Everything's ok, just keep going */
420 #define X_HANG 2 /* Wait for more commands before continuing */
421 #define X_SYNCMARK 3 /* Flush after sending a syncmark */
422 /*
423 * Constants of the protocol
424 */
425 #undef TRUE
426 #undef FALSE
427 #define TIDLEN 5 /* Significant length of tid's */
428 #define FHLEN 5 /* Significant length of fh's */
429 #define SYNOP 0201 /* Opcode for synchronous marks */
430 #define ASYNOP 0202 /* Opcode for asynchronous marks */
431 #define FALSE "NIL" /* False value in binary options */
432 #define TRUE "T" /* True value in binary options */
433 #define QBIN1 ((unsigned)0143150) /* First word of "QFASL" in SIXBIT */
434 #define QBIN2 071660 /* Second word of "QFASL" */
435 #define LBIN1 ((unsigned)0170023) /* First word of BIN file */
436 #define LBIN2LIMIT 100 /* Maximum value of second word of BIN file */
437
438 /*
439 * Definition of options
440 */
441 struct option options[] = {
442 /* o_name o_type o_value o_cant */
443 { "READ", O_BIT, O_READ, O_WRITE|O_PROBE },
444 { "WRITE", O_BIT, O_WRITE, O_READ|O_PROBE },
445 { "PROBE", O_BIT, O_PROBE, O_READ|O_WRITE },
446 { "CHARACTER", O_BIT, O_CHARACTER, O_BINARY|O_DEFAULT},
447 { "BINARY", O_BIT, O_BINARY, O_CHARACTER|O_DEFAULT},
448 { "BYTE-SIZE", O_NUMBER, O_BYTESIZE, O_CHARACTER },
449 { "RAW", O_BIT, O_RAW, O_BINARY|O_SUPER},
450 { "SUPER-IMAGE", O_BIT, O_SUPER, O_BINARY|O_RAW },
451 { "TEMPORARY", O_BIT, O_TEMPORARY, 0},
452 { "DELETED", O_BIT, O_DELETED, 0},
453 { "OLD", O_BIT, O_OLD, O_NEWOK },
454 { "NEW-OK", O_BIT, O_NEWOK, O_OLD },
455 { "DEFAULT", O_BIT, O_DEFAULT, O_BINARY|O_CHARACTER|O_PROBE|O_WRITE},
456 { "FAST", O_BIT, O_FAST, 0},
457 { "SORTED", O_BIT, O_SORTED, 0},
458 { "PRESERVE-DATES",O_BIT, O_PRESERVE, 0},
459 { "INHIBIT-LINKS",O_BIT, 0, 0},
460 { "PROBE-DIRECTORY",O_BIT, O_PROBEDIR, O_READ|O_WRITE },
461 { "ESTIMATED-LENGTH",O_NUMBER, O_ESTSIZE, O_READ|O_PROBE },
462 { "IF-EXISTS", O_EXISTS, O_IFEXISTS, O_READ|O_PROBE },
463 { "IF-DOES-NOT-EXIST",O_EXISTS, O_IFNEXISTS, O_READ|O_PROBE },
464 { "NO-EXTRA-INFO",O_BIT, 0, 0},
465 { NOSTR, },
466 };
467
468 /*
469 * Syntax definition - values for syntax strings
470 */
471 #define SP 1 /* Must be CHSP character */
472 #define NL 2 /* Must be CHNL character */
473 #define STRING 3 /* All characters until following character */
474 #define OPTIONS 4 /* Zero or more (SP, WORD), WORD in options */
475 #define NUMBER 5 /* [-]digits, base ten */
476 #define OPEND 6 /* Optional end of command */
477 #define PNAME 7 /* Property name */
478 #define PVALUE 8 /* Property value */
479 #define REPEAT 9 /* Repeat from last OPEND */
480 #define END 10 /* End of command, must be at end of args */
481 #define FHSKIP 11 /* Skip next if FH present - kludge for change properties */
482
483 unsigned char dcsyn[] = { STRING, SP, STRING, END };
484 unsigned char nosyn[] = { END };
485 unsigned char opensyn[] = { OPTIONS, NL, STRING, NL, END };
486 unsigned char possyn[] = { NUMBER, END };
487 unsigned char delsyn[] = { OPEND, NL, STRING, NL, END };
488 unsigned char rensyn[] = { NL, STRING, NL, OPEND, STRING, NL, END };
489 /*char setsyn[] = { NUMBER, SP, OPEND, NUMBER, END };*/
490 unsigned char logsyn[] = { OPEND, STRING, OPEND, SP, STRING, OPEND,
491 SP, STRING, END };
492 unsigned char dirsyn[] = { OPTIONS, NL, STRING, NL, END };
493 unsigned char compsyn[] = { OPTIONS, NL, STRING, NL, STRING, NL, END };
494 unsigned char changesyn[] = { NL, FHSKIP, 2, STRING, NL, OPEND,
495 PNAME, SP, PVALUE, NL, REPEAT };
496 unsigned char crdirsyn[] = { NL, STRING, NL, END };
497 unsigned char expsyn[] = { NL, STRING, NL, END };
498 unsigned char propsyn[] = { STRING, OPEND, NL, STRING, NL, END };
499 /*char crlsyn[] = { NL, STRING, NL, STRING, END }; */
500 /*
501 * Command definitions
502 */
503 void dataconn(register struct transaction *t);
504 void undataconn(register struct transaction *t);
505 void login(register struct transaction *t);
506 void fileopen(register struct transaction *t);
507 void getprops(register struct transaction *t);
508 void directory(register struct transaction *t);
509 void fileclose(register struct xfer *x, register struct transaction *t);
510 void filepos(register struct xfer *x, register struct transaction *t);
511 void filecontinue(register struct xfer *x, register struct transaction *t);
512 void delete(register struct transaction *t);
513 void xrename(register struct transaction *t);
514 void complete(register struct transaction *t);
515 void crdir(register struct transaction *t);
516 void expunge(register struct transaction *t);
517 void chngprop(register struct transaction *t);
518
519 int setbytesize();
520
521 struct command commands[] = {
522 /* c_name c_funct c_flags c_syntax */
523 { "DATA-CONNECTION", dataconn, C_FHCANT|C_NOLOG,dcsyn },
524 { "UNDATA-CONNECTION", undataconn, C_FHMUST|C_NOLOG,nosyn },
525 { "OPEN", fileopen, 0, opensyn },
526 { "CLOSE", fileclose, C_XFER|C_FHMUST,nosyn },
527 { "FILEPOS", filepos, C_XFER|C_FHINPUT,possyn },
528 { "DELETE", delete, 0, delsyn },
529 { "RENAME", xrename, 0, rensyn },
530 { "CONTINUE", filecontinue, C_XFER|C_FHMUST,nosyn },
531 { "EXPUNGE", expunge, C_FHCANT, expsyn },
532 /*{ "SET-BYTE-SIZE", setbytesize, C_XFER|C_FHINPUT,setsyn },*/
533 /*{ "ENABLE-CAPABILITIES", etc */
534 /*{ "DISABLE-CAPABILITIES", etc */
535 { "LOGIN", login, C_FHCANT|C_NOLOG,logsyn },
536 { "DIRECTORY", directory, C_FHINPUT, dirsyn },
537 { "COMPLETE", complete, C_FHCANT, compsyn },
538 { "CHANGE-PROPERTIES", chngprop, 0, changesyn },
539 { "CREATE-DIRECTORY", crdir, C_FHCANT, crdirsyn },
540 { "PROPERTIES", getprops, C_FHINPUT, propsyn },
541 { NOSTR },
542 };
543 /*
544 * Kludge for actually responding to the DIRECTORY command in the subtask.
545 */
546 void diropen(struct xfer *ax, register struct transaction *t);
547 struct command dircom = {
548 "DIRECTORY", diropen, 0, 0
549 };
550
551 void propopen(register struct xfer *x, register struct transaction *t);
552 struct command propcom = {
553 "PROPERTIES", propopen, 0, 0
554 };
555
556 /*
557 * Property definitions for change-properties.
558 */
559 char *getdev(register struct stat *s, register char *cp);
560 char *getblock(struct stat *s, char *cp);
561 char *getspace(struct stat *s, char *cp);
562 char *getbyte(struct stat *s, char *cp);
563 char *getsize(register struct stat *s, register char *cp);
564 char *getmdate(register struct stat *s, register char *cp);
565 char *getrdate(register struct stat *s, register char *cp);
566 char *getdir(register struct stat *s, register char *cp);
567 char *getname(register struct stat *s, register char *cp);
568 char *getprot(register struct stat *s, register char *cp);
569 char *getsprops(struct stat *s, register char *cp);
570 char *tnum(register char *cp, char delim, int *ip);
571
572 char
573 *getcdate();
574 int putprot(register struct stat *s, char *file, char *newprot);
575 int putname(register struct stat *s, char *file, char *newname);
576 int putmdate(register struct stat *s, char *file, char *newtime, register struct xfer *x);
577 int putrdate(register struct stat *s, char *file, char *newtime, register struct xfer *x);
578
579 static char *xgetbsize(struct stat *s, char *cp);
580
581 #define P_GET 1
582 #define P_DELAY 2
583 #define P_GLOBAL 4
584
585 struct property {
586 char *p_indicator; /* Property name */
587 int p_flags; /* Attributes of this property */
588 char *(*p_get)(); /* Function to get the property */
589 int (*p_put)(); /* Function to set the property */
590 } properties[] = {
591 /* name flags */
592 { "AUTHOR", P_GET, getname, putname, },
593 { "PHYSICAL-VOLUME", P_GET, getdev, 0, },
594 { "PROTECTION", P_GET, getprot, putprot, },
595 { "DISK-SPACE-DESCRIPTION", P_GLOBAL, getspace, 0, },
596 { "BLOCK-SIZE", P_GLOBAL, getblock, 0, },
597 { "BYTE-SIZE", P_GET, getbyte, 0, },
598 { "LENGTH-IN-BLOCKS", P_GET, xgetbsize, 0, },
599 { "LENGTH-IN-BYTES", P_GET, getsize, 0, },
600 { "CREATION-DATE", P_GET, getmdate, putmdate, },
601 { "MODIFICATION-DATE", P_GET|P_DELAY, getmdate, putmdate, },
602 { "REFERENCE-DATE", P_GET|P_DELAY, getrdate, putrdate, },
603 { "SETTABLE-PROPERTIES", P_GLOBAL, getsprops, 0, },
604 /*{ "PHYSICAL-VOLUME-FREE-BLOCKS", P_GLOBAL, getfree, 0, },*/
605 { "DIRECTORY", P_GET, getdir, 0, },
606 { 0, 0, 0, 0, },
607 };
608 /*
609 * Globals
610 */
611 //struct chstatus chst; /* Status buffer for connections */
612 char errtype; /* Error type if not E_COMMAND */
613 char *errstring; /* Error message if non-standard */
614 char errbuf[ERRSIZE + 1]; /* Buffer for building error messages */
615 char *home; /* Home directory, after logged in */
616 char *cwd; /* Current working directory, if one */
617 int protocol = 1; /* Which number argument after FILE in RFC */
618 int mypid; /* Pid of controlling process */
619 struct timeb timeinfo;
620 //struct chlogin mylogin; /* Record for login */
621 extern int errno; /* System call error code */
622
623 /*
624 * Non-integer return types from functions
625 */
626 /*char *savestr(), *malloc(), *strcpy(), *sprintf(), *rindex(), *strcat();*/
627 char *savestr(char *s);
628 char *fullname(register struct passwd *p);
629 char *downcase(char *string);
630 char *crypt();
631 /*long lseek(), fseek(), tell();*/
632 struct passwd *getpwnam(), *getpwuid();
633 char *tempfile(char *dname);
634 struct tm *localtime();
635 struct transaction *getwork(chaos_connection *conn);
636 char **glob();
637 struct xfer *makexfer(register struct transaction *t, long options);
638 void finish(int arg);
639 void xcommand(register struct transaction *t);
640 void tinit(register struct transaction *t);
641 void tfree(register struct transaction *t);
642 void xcheck(void);
643 int parseargs(unsigned char *args, struct command *c, register struct transaction *t);
644 void error(struct transaction *t, char *fh, int code);
645 void ainit(register struct cmdargs *a);
646 int string(register unsigned char **args, unsigned char *term, unsigned char **dest);
647 int getxoption(register struct cmdargs *a, int xvalue, char **args);
648 void afree(register struct cmdargs *a);
649 void pfree(register struct plist *p);
650 void xfree(register struct xfer *x);
651 void fatal(char *fmt, ...);
652 int parsepath(register char *path, char **dir, char **real, int blankok);
653 int startxfer(struct xfer *ax);
654 void xflush(register struct xfer *x);
655 void backfile(register char *file);
656 int mv(char *from, char *fromdir, char *to, char *todir);
657 int prefix(register char *in, register char *new);
658 void incommon(register char *old, register char *new);
659 int parsetime(register char *cp, register time_t *t);
660 int dcanon(char *cp, int blankok);
661 int dowork(register struct xfer *x);
662 ssize_t xpread(register struct xfer *x);
663 int xpweof(register struct xfer *x);
664 int xpwrite(register struct xfer *x);
665 int xbwrite(register struct xfer *x);
666 void to_lispm(register struct xfer *x);
667 void from_lispm(register struct xfer *x);
668 void processdata(chaos_connection *conn);
669 void processmini(chaos_connection *conn);
670
671 #if defined(MAP_SITE_TREE_DIRECTORY)
672 static char *treeroot;
673
674 void
675 settreeroot(const char *root)
676 {
677 treeroot = strdup(root);
678 if (treeroot[strlen(treeroot)] == '/')
679 treeroot[strlen(treeroot)] = '\0';
680
681 printf("settreeroot: '%s'\n", treeroot);
682 }
683 #endif
684
685 static void
686 dumpbuffer(u_char *buf, ssize_t cnt)
687 {
688 ssize_t j;
689 int offset, skipping;
690 char cbuf[17];
691 char line[80];
692
693 offset = 0;
694 skipping = 0;
695 while (cnt > 0) {
696 if (offset > 0 && memcmp(buf, buf-16, 16) == 0) {
697 skipping = 1;
698 } else {
699 if (skipping) {
700 skipping = 0;
701 fprintf(stderr,"...\n");
702 }
703 }
704
705 if (!skipping) {
706 for (j = 0; j < 16; j++) {
707 char *pl = line+j*3;
708
709 if (j >= cnt) {
710 strcpy(pl, "xx ");
711 cbuf[j] = 'x';
712 } else {
713 sprintf(pl, "%02x ", buf[j]);
714 cbuf[j] = buf[j] < ' ' ||
715 buf[j] > '~' ? '.' : (char)buf[j];
716 }
717 pl[3] = 0;
718 }
719 cbuf[16] = 0;
720
721 fprintf(stderr,"%08x %s %s\n", offset, line, cbuf);
722 }
723
724 buf += 16;
725 cnt -= 16;
726 offset += 16;
727 }
728
729 if (skipping) {
730 fprintf(stderr,"%08x ...\n", offset-16);
731 }
732 fflush(stderr);
733 }
734
735 #if defined(OSX)
736
737 void processdata(chaos_connection *conn)
738 {
739 dispatch_async(dispatch_get_global_queue(0, 0), ^{
740 register struct transaction *t;
741
742 while ((t = getwork(conn))) {
743 if (t->t_command->c_flags & C_XFER)
744 xcommand(t);
745 else
746 (*t->t_command->c_func)(t);
747 }
748 });
749 }
750
751 #else // !defined(OSX)
752
753 static void *_processdata(void *conn)
754 {
755 register struct transaction *t;
756
757 while ((t = getwork((chaos_connection *)conn))) {
758 if (t->t_command->c_flags & C_XFER)
759 xcommand(t);
760 else
761 (*t->t_command->c_func)(t);
762 }
763 return 0;
764 }
765
766 static pthread_t processdata_thread;
767
768 void processdata(chaos_connection *conn)
769 {
770 pthread_create(&processdata_thread, NULL, _processdata, (void *)conn);
771 }
772
773 #endif // defined(OSX)
774
775 /*
776 00000000 00 80 18 00 04 01 00 01 01 01 45 37 01 00 01 00 ..........E7....
777 00000010 54 31 34 33 34 20 20 4c 4f 47 49 4e 20 4c 49 53 T1434 LOGIN LIS
778 00000020 50 4d 20 62 72 61 64 20 xx xx xx xx xx xx xx xx PM brad xxxxxxxx
779 */
780 unsigned char pkt[] = {
781 // 0x00, 0x80, 0x18, 0x00, 0x04, 0x01, 0x00, 0x01,
782 // 0x01, 0x01, 0x45, 0x37, 0x01, 0x00, 0x01, 0x00,
783 0x80,
784 0x54, 0x31, 0x34, 0x33, 0x34, 0x20, 0x20, 0x4c,
785 0x4f, 0x47, 0x49, 0x4e, 0x20, 0x4c, 0x49, 0x53,
786 0x50, 0x4d, 0x20, 0x62, 0x72, 0x61, 0x64, 0x20
787 };
788
789 /*
790 * Getwork - read a command from the control connection (standard input),
791 * parse it, including all arguments (as much as possible),
792 * and do any possible error checking. Any errors cause rejection
793 * here, and such commands are not returned.
794 */
795 struct transaction *
796 getwork(chaos_connection *conn)
797 {
798 register struct transaction *t;
799 register struct command *c;
800 register unsigned char *cp;
801 char *fhname, *cname;
802 unsigned char save;
803 int length;
804 int errcode;
805 chaos_packet *packet;
806
807 for (;;) {
808 if ((t = salloc(transaction)) == TNULL)
809 {
810 fatal(NOMEM);
811 return NULL;
812 }
813
814 tinit(t);
815 fhname = "";
816 errcode = BUG; /* Default error is bad syntax */
817
818 packet = chaos_connection_dequeue(conn);
819 if (packet == 0)
820 {
821 tfree(t);
822 return NULL;
823 }
824
825 t->t_packet = packet;
826 t->t_connection = conn;
827
828 length = packet->length & 0x3ff;
829
830 packet->data[length] = '\0';
831 #if 1
832 log(LOG_INFO, "FILE: pkt(%d):%.*s\n", ((packet->opcode & 0xff00) >> 8), length-1,
833 packet->data);
834 #endif
835 switch (((packet->opcode & 0xff00) >> 8)) {
836 case EOFOP:
837 tfree(t);
838 return TNULL;
839 case CLSOP:
840 case LOSOP:
841 log(LOG_INFO, "FILE: Close pkt: '%s'\n", packet->data);
842 t->t_connection->state = cs_closed;
843 tfree(t);
844 return TNULL;
845 case RFCOP:
846 tfree(t);
847 return TNULL;
848 case DATOP:
849 break;
850 default:
851 printf("FILE: Bad op: 0%o\n", ((packet->opcode & 0xff00) >> 8));
852 tfree(t);
853 return TNULL;
854 }
855 for (cp = (unsigned char *)packet->data; *cp != CHSP; )
856 if (*cp++ == '\0') {
857 errstring = "Missing transaction id";
858 goto cmderr;
859 }
860 *cp = '\0';
861 t->t_tid = savestr((char *)packet->data);
862 if (*++cp != CHSP) {
863 struct file_handle *f;
864
865 for (fhname = (char *)cp; *++cp != CHSP; )
866 if (*cp == '\0') {
867 errstring =
868 "No command after file handle";
869 goto cmderr;
870 }
871 *cp = '\0';
872 for (f = file_handles; f; f = f->f_next)
873 if (strncmp(fhname, f->f_name, FHLEN) == 0)
874 break;
875 if (f == FNULL) {
876 (void)sprintf(errstring = errbuf,
877 "Unknown file handle: %s", fhname);
878 goto cmderr;
879 }
880 t->t_fh = f;
881 }
882 for (cname = (char *)++cp;
883 *cp != '\0' && *cp != CHSP && *cp != CHNL;)
884 cp++;
885 save = *cp;
886 *cp = '\0';
887 if (*cname == '\0') {
888 errstring = "Null command name";
889 goto cmderr;
890 }
891
892 log(LOG_INFO, "FILE: command %s\n", cname);
893 for (c = commands; c->c_name; c++)
894 if (strcmp(cname, c->c_name) == 0)
895 break;
896 if (c == CNULL) {
897 (void)sprintf(errstring = errbuf,
898 "Unknown command: %s", cname);
899 errcode = UKC;
900 goto cmderr;
901 }
902 if (home == NOSTR && (c->c_flags & C_NOLOG) == 0) {
903 errcode = NLI;
904 goto cmderr;
905 }
906 t->t_command = c;
907 *cp = save;
908 if (t->t_fh == FNULL) {
909 if (c->c_flags & (C_FHMUST|C_FHINPUT|C_FHOUTPUT)) {
910 (void)sprintf(errstring = errbuf,
911 "Missing file handle on command: %s",
912 cname);
913 goto cmderr;
914 }
915 } else if (c->c_flags & C_FHCANT) {
916 (void)sprintf(errstring = errbuf,
917 "File handle present on command: %s",
918 cname);
919 goto cmderr;
920 } else if ((c->c_flags & C_FHINPUT &&
921 t->t_fh->f_type != F_INPUT) ||
922 (c->c_flags & C_FHOUTPUT &&
923 t->t_fh->f_type != F_OUTPUT)) {
924 (void)sprintf(errstring = errbuf,
925 "Wrong direction file handle (%s) for command: %s",
926 fhname, cname);
927 goto cmderr;
928 }
929 if (*cp == ' ')
930 cp++;
931 if ((errcode = parseargs(cp, c, t)) == 0)
932 return t;
933 cmderr:
934 log(LOG_INFO, "FILE: %s\n", errstring);
935 error(t, fhname, errcode);
936 }
937 return t;
938 }
939 /*
940 * Parse the argument part of the command, returning an error code if
941 * an error was found.
942 */
943 int
944 parseargs(unsigned char *args, struct command *c, register struct transaction *t)
945 {
946 register unsigned char *syntax;
947 register struct cmdargs *a;
948 struct plist *p;
949 struct option *o;
950 int nnums, nstrings, errcode;
951 long n;
952
953 t->t_args = ANULL;
954 if (c->c_syntax[0] == END) {
955 if (args[0] == '\0')
956 return 0;
957 else {
958 errstring = "Arguments present where none expected";
959 return BUG;
960 }
961 }
962 if ((a = salloc(cmdargs)) == ANULL)
963 fatal(NOMEM);
964 /* From here on, goto synerr for errors so A gets freed */
965 errcode = BUG;
966 ainit(a);
967 nstrings = nnums = 0;
968 for (syntax = c->c_syntax; *syntax != END; ) {
969 switch (*syntax++) {
970 case FHSKIP:
971 if (t->t_fh != FNULL)
972 syntax += *syntax + 1;
973 else
974 syntax++;
975 continue;
976 case SP:
977 if (*args++ != CHSP) {
978 (void)sprintf(errstring = errbuf,
979 "Space expected where 0%o (octal) occurred",
980 args[-1]);
981 goto synerr;
982 }
983 continue;
984 case NL:
985 if (*args++ != CHNL) {
986 (void)sprintf(errstring = errbuf,
987 "Newline expected where 0%o (octal) occurred",
988 args[-1]);
989 goto synerr;
990 }
991 continue;
992 case OPEND:
993 if (*args == '\0')
994 break;
995 continue;
996 case REPEAT:
997 while (*--syntax != OPEND)
998 ;
999 continue;
1000 case NUMBER:
1001 if (!isdigit(*args)) {
1002 (void)sprintf(errstring = errbuf,
1003 "Digit expected where 0%o (octal) occurred",
1004 args[0]);
1005 goto synerr;
1006 }
1007 n = 0;
1008 while (isdigit(*args)) {
1009 n *= 10;
1010 n += *args++ - '0';
1011 }
1012 a->a_numbers[nnums++] = n;
1013 continue;
1014 case STRING:
1015 if ((errcode = string(&args, syntax,
1016 (unsigned char **)&a->a_strings[nstrings++])))
1017 goto synerr;
1018 continue;
1019 case PNAME:
1020 if ((p = a->a_plist) != PNULL && p->p_value == NOSTR) {
1021 errstring =
1022 "Property name expected when already given";
1023 goto synerr;
1024 }
1025 p = salloc(plist);
1026 if (p) {
1027 if ((errcode = string(&args, syntax, (unsigned char **)&p->p_name))) {
1028 sfree(p);
1029 goto synerr;
1030 }
1031 p->p_next = a->a_plist;
1032 a->a_plist = p;
1033 p->p_value = NOSTR;
1034 }
1035 else
1036 fatal(NOMEM);
1037 continue;
1038 case PVALUE:
1039 if ((p = a->a_plist) == PNULL || p->p_value != NOSTR) {
1040 errstring =
1041 "Property value expected when no name given";
1042 goto synerr;
1043 }
1044 if ((errcode = string(&args, syntax, (unsigned char **)&p->p_value)))
1045 goto synerr;
1046 continue;
1047 case OPTIONS:
1048 while (*args != '\0' && *args != CHNL) {
1049 char *oname;
1050
1051 while (*args == ' ')
1052 args++;
1053 if ((errcode = string(&args, (unsigned char *)"", (unsigned char **)&oname)))
1054 goto synerr;
1055 if (*oname == '\0')
1056 continue;
1057 for (o = options; o->o_name; o++)
1058 if (strcmp(oname, o->o_name) == 0)
1059 break;
1060 if (o->o_name == NOSTR) {
1061 log(LOG_ERR, "FILE: UOO:'%s'\n",
1062 oname);
1063 (void)sprintf(errstring = errbuf,
1064 "Unknown open option: %s",
1065 oname);
1066 free(oname);
1067 afree(a);
1068 return UUO;
1069 }
1070 free(oname);
1071 switch (o->o_type) {
1072 case O_BIT:
1073 a->a_options |= o->o_value;
1074 break;
1075 case O_NUMBER:
1076 if (*args++ != CHSP ||
1077 !isdigit(*args)) {
1078 (void)sprintf(errstring = errbuf,
1079 "Digit expected where 0%o (octal) occurred",
1080 args[-1]);
1081 goto synerr;
1082 }
1083 n = 0;
1084 while (isdigit(*args)) {
1085 n *= 10;
1086 n += *args++ - '0';
1087 }
1088 a->a_numbers[o->o_value] = n;
1089 break;
1090 case O_EXISTS:
1091 if ((errcode = getxoption(a, (int)o->o_value, (char **)&args)))
1092 goto synerr;
1093 break;
1094 }
1095 }
1096 for (o = options; o->o_name; o++)
1097 if (o->o_type == O_BIT &&
1098 (o->o_value & a->a_options) != 0 &&
1099 (o->o_cant & a->a_options)) {
1100 errcode = ICO;
1101 goto synerr;
1102 }
1103 continue;
1104 default:
1105 fatal("Bad token type in syntax");
1106 }
1107 break;
1108 }
1109 t->t_args = a;
1110 return 0;
1111 synerr:
1112 afree(a);
1113 return errcode;
1114 }
1115
1116 int
1117 getxoption(register struct cmdargs *a, int xvalue, char **args)
1118 {
1119 register struct xoption *x;
1120 int errcode;
1121 unsigned char *xname;
1122
1123 if (*(*args)++ != CHSP) {
1124 errstring = "Missing value for open option";
1125 return MSC;
1126 }
1127 if ((errcode = string((unsigned char **)args, (unsigned char *)"", &xname)))
1128 return errcode;
1129 if (xname == 0 || *xname == '\0') {
1130 errstring = "Empty value for open option";
1131 if (xname)
1132 free(xname);
1133 return MSC;
1134 }
1135 for (x = xoptions; x->x_name; x++)
1136 if (strcmp((char *)xname, x->x_name) == 0) {
1137 if (x->x_cant == xvalue)
1138 {
1139 if (xname)
1140 free(xname);
1141 return ICO;
1142 }
1143 a->a_exists[xvalue] = (char)x->x_value;
1144 if (xname)
1145 free(xname);
1146 return 0;
1147 }
1148 if (xname)
1149 free(xname);
1150 return UUO;
1151 }
1152 /*
1153 * Return the saved string starting at args and ending at the
1154 * point indicated by *term. Return the saved string, and update the given
1155 * args pointer to point at the terminating character.
1156 * If term is null, terminate the string on CHSP, CHNL, or null.
1157 */
1158 int
1159 string(register unsigned char **args, unsigned char *term, unsigned char **dest)
1160 {
1161 register unsigned char *cp;
1162 register unsigned char *s;
1163 unsigned char delim, save;
1164
1165 if (*term == OPEND)
1166 term++;
1167
1168 switch (*term) {
1169 case SP:
1170 delim = CHSP;
1171 break;
1172 case NL:
1173 delim = CHNL;
1174 break;
1175 case END:
1176 delim = '\0';
1177 break;
1178 case 0:
1179 delim = '\0';
1180 break;
1181 default:
1182 delim = '\0';
1183 fatal("Bad delimiter for string: %o", *term);
1184 }
1185 for (cp = *args; *cp != delim; cp++)
1186 if (*cp == '\0' || (*term == 0 && (*cp == CHSP || *cp == CHNL)))
1187 break;
1188 save = *cp;
1189 *cp = '\0';
1190 s = (unsigned char *)savestr((char *)*args);
1191 *cp = save;
1192 *args = cp;
1193 if (dest)
1194 *dest = s;
1195 else
1196 free(s);
1197 return 0;
1198 }
1199
1200 /*
1201 * Initialize the transaction structure.
1202 */
1203 void
1204 tinit(register struct transaction *t)
1205 {
1206 if (t) {
1207 t->t_tid = NOSTR;
1208 t->t_fh = FNULL;
1209 t->t_command = CNULL;
1210 t->t_args = ANULL;
1211 t->t_connection = 0;
1212 t->t_packet = 0;
1213 }
1214 }
1215
1216 /*
1217 * Free storage specifically associated with a transaction (not file handles)
1218 */
1219 void
1220 tfree(register struct transaction *t)
1221 {
1222 if (t->t_tid)
1223 free(t->t_tid);
1224 if (t->t_args)
1225 afree(t->t_args);
1226 if (t->t_packet)
1227 free(t->t_packet);
1228 sfree(t);
1229 }
1230 /*
1231 * Free storage in an argumet structure
1232 */
1233 void
1234 afree(register struct cmdargs *a)
1235 {
1236 register char **ap, i;
1237
1238 for (ap = a->a_strings, i = 0; i < MAXSTRINGS; ap++, i++)
1239 if (*ap)
1240 free(*ap);
1241 pfree(a->a_plist);
1242 sfree(a);
1243 }
1244 /*
1245 * Free storage in a plist.
1246 */
1247 void
1248 pfree(register struct plist *p)
1249 {
1250 register struct plist *np;
1251
1252 while (p) {
1253 if (p->p_name)
1254 free(p->p_name);
1255 if (p->p_value)
1256 free(p->p_value);
1257 np = p->p_next;
1258 sfree(p);
1259 p = np;
1260 }
1261 }
1262
1263 /*
1264 * Make a static copy of the given string.
1265 */
1266 char *
1267 savestr(char *s)
1268 {
1269 register char *p;
1270
1271 if (s == 0)
1272 return 0;
1273
1274 p = malloc((unsigned)(strlen(s) + 1));
1275 if (p)
1276 (void)strcpy(p, s);
1277 else
1278 fatal(NOMEM);
1279 return p;
1280 }
1281
1282 /*
1283 * Initialize an argument struct
1284 */
1285 void
1286 ainit(register struct cmdargs *a)
1287 {
1288 register int i;
1289
1290 a->a_options = 0;
1291 for (i = 0; i < MAXSTRINGS; i++)
1292 a->a_strings[i] = NOSTR;
1293 for (i = 0; i < O_MAXNUMS; i++)
1294 a->a_numbers[i] = 0;
1295 for (i = 0; i < O_MAXEXS; i++)
1296 a->a_exists[i] = O_XNONE;
1297 a->a_plist = PNULL;
1298 }
1299 /*
1300 * Blow me away completely. I am losing.
1301 */
1302 /* VARARGS1*/
1303 void
1304 fatal(char *fmt, ...)
1305 {
1306 va_list ap;
1307
1308 log(LOG_ERR, "Fatal error in chaos file server: ");
1309 va_start(ap, fmt);
1310 vfprintf(stderr, fmt, ap);
1311 va_end(ap);
1312 log(LOG_ERR, "\n");
1313 fflush(stderr);
1314
1315 if (getpid() != mypid)
1316 (void)kill(mypid, SIGTERM);
1317
1318 finish(0);
1319 }
1320
1321 /*
1322 * Respond to the given transaction, including the given results string.
1323 * If the result string is non-null a space is prepended
1324 */
1325 static void
1326 respond(register struct transaction *t, char *results)
1327 {
1328 char data[512];
1329
1330 (void)sprintf(data, "%s %s %s%s%s", t->t_tid,
1331 t->t_fh != FNULL ? t->t_fh->f_name : "",
1332 t->t_command->c_name, results != NOSTR ? " " : "",
1333 results != NOSTR ? results : "");
1334
1335 chaos_packet *answer = chaos_allocate_packet(t->t_connection, CHAOS_OPCODE_DATA, (int)strlen(data));
1336
1337 memcpy(answer->data, data, strlen(data));
1338
1339 chaos_connection_queue(t->t_connection, answer);
1340
1341 tfree(t);
1342 }
1343
1344 /*
1345 * The transaction found an error, inform the other end.
1346 * If errstring has been set, use it as the message, otherwise use the
1347 * standard one.
1348 * If errtype has been set, use it as the error type instead of E_COMMAND.
1349 */
1350 void
1351 error(struct transaction *t, char *fh, int code)
1352 {
1353 register struct file_error *e = &errors[code];
1354 chaos_packet *error;
1355 char data[512];
1356
1357 (void)sprintf((char *)data, "%s %s ERROR %s %c %s", t->t_tid, fh,
1358 e->e_code, errtype ? errtype : E_COMMAND,
1359 errstring ? errstring : e->e_string);
1360
1361 error = chaos_allocate_packet(t->t_connection, CHAOS_OPCODE_DATA, (int)strlen(data));
1362
1363 #if 1
1364 log(LOG_INFO, "FILE: error; %s\n", data);
1365 #endif
1366 errstring = NOSTR;
1367 errtype = 0;
1368
1369 memcpy(error->data, data, strlen(data));
1370
1371 chaos_connection_queue(t->t_connection, error);
1372
1373 tfree(t);
1374 }
1375
1376 /*
1377 * Send a synchronous mark on the given file handle.
1378 * It better be for output!
1379 */
1380 static int
1381 syncmark(register struct file_handle *f)
1382 {
1383 if (f->f_type != F_INPUT)
1384 fatal("Syncmark");
1385
1386 chaos_packet *packet = chaos_allocate_packet(f->f_connection, SYNOP, 0);
1387
1388 chaos_connection_queue(f->f_connection, packet);
1389
1390 if (log_verbose) {
1391 log(LOG_INFO, "FILE: wrote syncmark to net\n");
1392 }
1393 return 0;
1394 }
1395
1396
1397 /*
1398 * Here are all the "top level" commands that don't relate to file system
1399 * operation at all, but only exists for data connection management and
1400 * user validation.
1401 */
1402
1403 /*
1404 * Create a new data connection. Output file handle (second string argument
1405 * is the contact name the other end is listening for. We must send an RFC.
1406 * The waiting for the new connection is done synchronously, and thus prevents
1407 * tha handling of any other commands for a bit. It should, if others already
1408 * exist, create a transfer task, just for the purpose of waiting. Yick.
1409 */
1410 void
1411 dataconn(register struct transaction *t)
1412 {
1413 register struct file_handle *ifh, *ofh;
1414 char *ifhname, *ofhname;
1415 int fd = -1;
1416
1417 ifhname = t->t_args->a_strings[0];
1418 ofhname = t->t_args->a_strings[1];
1419
1420 /*
1421 * Make sure that our "new" file handle names are really new.
1422 */
1423 for (ifh = file_handles; ifh; ifh = ifh->f_next)
1424 if (strcmp(ifhname, ifh->f_name) == 0 ||
1425 strcmp(ofhname, ifh->f_name) == 0) {
1426 errstring = "File handle already exists";
1427 error(t, "", BUG);
1428 return;
1429 }
1430
1431 extern int chaos_addr;
1432 chaos_connection *conn = chaos_open_connection(chaos_addr, ofhname, 2, 1, 0);
1433
1434 ifh = salloc(file_handle);
1435 ofh = salloc(file_handle);
1436 if (ifh) {
1437 ifh->f_fd = fd;
1438 ifh->f_type = F_INPUT;
1439 ifh->f_name = savestr(ifhname);
1440 ifh->f_xfer = XNULL;
1441 ifh->f_other = ofh;
1442 ifh->f_next = file_handles;
1443 ifh->f_connection = conn;
1444 file_handles = ifh;
1445 }
1446 else
1447 fatal(NOMEM);
1448 if (ofh) {
1449 ofh->f_fd = fd;
1450 ofh->f_type = F_OUTPUT;
1451 ofh->f_name = savestr(ofhname);
1452 ofh->f_xfer = XNULL;
1453 ofh->f_other = ifh;
1454 ofh->f_next = file_handles;
1455 ofh->f_connection = conn;
1456 file_handles = ofh;
1457 }
1458 else
1459 fatal(NOMEM);
1460
1461 respond(t, NOSTR);
1462 }
1463
1464 /*
1465 * Close the data connection indicated by the file handle.
1466 */
1467 void
1468 undataconn(register struct transaction *t)
1469 {
1470 register struct file_handle *f, *of;
1471
1472 f = t->t_fh;
1473 if (f->f_xfer != XNULL || f->f_other->f_xfer != XNULL) {
1474 errstring =
1475 "The data connection to be removed is still in use";
1476 error(t, f->f_name, BUG);
1477 } else {
1478 (void)close(f->f_fd);
1479 if (file_handles == f)
1480 file_handles = f->f_next;
1481 else {
1482 for (of = file_handles; of && of->f_next != f; of = of->f_next)
1483 if (of->f_next == FNULL)
1484 fatal(BADFHLIST);
1485 if (of)
1486 of->f_next = f->f_next;
1487 }
1488 if (file_handles == f->f_other)
1489 file_handles = f->f_other->f_next;
1490 else {
1491 for (of = file_handles; of && of->f_next != f->f_other; of = of->f_next)
1492 if (of->f_next == FNULL)
1493 fatal(BADFHLIST);
1494 if (of)
1495 of->f_next = f->f_other->f_next;
1496 }
1497
1498 // need to respond before we free the filehandle
1499 respond(t, NOSTR);
1500
1501 chaos_delete_connection(f->f_connection);
1502 free(f->f_name);
1503 of = f->f_other;
1504 free((char *)f);
1505 free(of->f_name);
1506 free((char *)of);
1507 }
1508 }
1509
1510 #ifdef PRIVHOSTS
1511 /* 4/29/85 Cory Myers
1512 * allow logins without passwords from privileged hosts
1513 */
1514
1515 char *privileged_hosts[] = {"mit-tweety-pie", "mit-daffy-duck"};
1516 #define NUM_PRIVILEGED_HOSTS (sizeof(privileged_hosts)/sizeof(char *))
1517 #endif
1518
1519 static int
1520 pwok(struct passwd *p, char *pw)
1521 {
1522 return 1;
1523 }
1524
1525 /*
1526 * Process a login command... verify the users name and
1527 * passwd.
1528 */
1529 void
1530 login(register struct transaction *t)
1531 {
1532 register struct passwd *p;
1533 register struct cmdargs *a;
1534 char *name;
1535 char response[CHMAXDATA];
1536
1537 log(LOG_INFO, "FILE: login()\n");
1538
1539 #ifdef PRIVHOSTS
1540 /* 4/29/85 Cory Myers
1541 * allow logins without passwords from privileged hosts
1542 */
1543 int host_name,privileged_host;
1544
1545 privileged_host = 0;
1546 for (host_name = 0; host_name < NUM_PRIVILEGED_HOSTS; host_name++) {
1547 if (strcmp(privileged_hosts[host_name],chaos_name(mylogin.cl_haddr))
1548 == 0) {
1549 privileged_host = 1;
1550 break;
1551 }
1552 }
1553 #endif
1554
1555 a = t->t_args;
1556 if ((name = a->a_strings[0]) == NOSTR) {
1557 log(LOG_INFO, "FILE exiting due to logout\n");
1558 finish(0);
1559 #if 0
1560 } else if (home != NOSTR) {
1561 // errstring = "You are already logged in.";
1562 // error(t, "", BUG);
1563 #endif
1564 } else if (*name == '\0' || (p = getpwnam(downcase(name))) == (struct passwd *)0) {
1565 log(LOG_INFO, "FILE: login() no user '%s'\n", name);
1566 errstring = "Login incorrect.";
1567 error(t, "", UNK);
1568 } else if (p->pw_passwd == NOSTR || *p->pw_passwd == '\0') {
1569 /* User MUST have a passwd */
1570 errstring = "Invalid account";
1571 error(t, "", MSC);
1572 } else if (0 && p->pw_passwd != NOSTR && *p->pw_passwd != '\0' &&
1573 #ifdef PRIVHOSTS
1574 /* allow logins without passwords from privileged hosts */
1575 !privileged_host &&
1576 #endif
1577 (a->a_strings[1] == NOSTR || pwok(p, a->a_strings[1]) == 0)) {
1578 log(LOG_INFO, "FILE: %s %s failed", name, a->a_strings[1]);
1579 log(LOG_INFO, "p->pw_passwd %p, *p->pw_passwd %02x\n",
1580 p->pw_passwd, p->pw_passwd ? *p->pw_passwd : 0);
1581 error(t, "", IP);
1582 } else if (p->pw_uid != 0 && access(NOLOGIN, F_OK) == 0) {
1583 errstring = "All logins are disabled, system shutting down";
1584 error(t, "", MSC);
1585 } else {
1586 log(LOG_INFO, "FILE: login() pw ok\n");
1587 home = savestr(p->pw_dir);
1588 cwd = savestr(home);
1589 #if 0
1590 umask(0);
1591 #if defined(BSD42) || defined(linux) || defined(OSX)
1592 (void)initgroups(p->pw_name, (int)p->pw_gid);
1593 #else /*!BSD42*/
1594 (void)setgid(p->pw_gid);
1595 #endif /*!BSD42*/
1596 (void)setuid(p->pw_uid);
1597 #endif
1598
1599 (void)sprintf(response, "%s %s/%c%s%c", p->pw_name, p->pw_dir,
1600 CHNL, fullname(p), CHNL);
1601
1602 #if 0
1603 register int ufd;
1604
1605 strncpy(mylogin.cl_user, p->pw_name, sizeof(mylogin.cl_user));
1606 if ((ufd = open(FILEUTMP, 1)) >= 0) {
1607 (void)lseek(ufd,
1608 (off_t)(mylogin.cl_cnum * sizeof(struct chlogin)),
1609 0);
1610 (void)write(ufd, (char *)&mylogin, sizeof(mylogin));
1611 (void)close(ufd);
1612 }
1613 #endif
1614 log(LOG_INFO, "FILE: login() responding\n");
1615 respond(t, response);
1616 #if 0
1617 log(LOG_NOTICE, "FILE: logged in as %s from host %s\n",
1618 p->pw_name, chaos_name(mylogin.cl_haddr));
1619 #endif
1620 #if 0
1621 {
1622 char str[50];
1623
1624 sprintf(str, "/usr/local/f @%s",
1625 chaos_name(mylogin.cl_haddr));
1626 strcat(str, " |/usr/local/logger -t FILE -p %d",
1627 LOG_NOTICE);
1628 system(str);
1629 }
1630 #endif
1631 }
1632 log(LOG_INFO, "FILE: login() done\n");
1633 }
1634 /*
1635 * Generate the full name from the password file entry, according to
1636 * the current "finger" program conventions. This code was sort of
1637 * lifted from finger and needs to be kept in sync with it...
1638 */
1639 char *
1640 fullname(register struct passwd *p)
1641 {
1642 static char fname[100];
1643 register char *cp;
1644 register char *gp;
1645
1646 gp = p->pw_gecos;
1647 cp = fname;
1648 if (*gp == '*')
1649 gp++;
1650 while (*gp != '\0' && *gp != ',') {
1651 if( *gp == '&' ) {
1652 char *lp = p->pw_name;
1653
1654 if (islower(*lp))
1655 *cp++ = (char)toupper(*lp++);
1656 while (*lp)
1657 *cp++ = *lp++;
1658 } else
1659 *cp++ = *gp;
1660 gp++;
1661 }
1662 *cp = '\0';
1663 for (gp = cp; gp > fname && *--gp != ' '; )
1664 ;
1665 if (gp == fname)
1666 return fname;
1667 *cp++ = ',';
1668 *cp++ = ' ';
1669 *gp = '\0';
1670 strcpy(cp, fname);
1671 return ++gp;
1672 }
1673
1674 char *
1675 downcase(char *string)
1676 {
1677 register char *cp;
1678
1679 for (cp = string; *cp; cp++)
1680 if (isupper(*cp))
1681 *cp = (char)tolower(*cp);
1682 return string;
1683 }
1684
1685 /*
1686 * Here are the major top level commands that create transfers,
1687 * either of data or directory contents
1688 */
1689 /*
1690 * Open a file.
1691 * Unless a probe is specified, a transfer is created, and started.
1692 */
1693 void
1694 fileopen(register struct transaction *t)
1695 {
1696 register struct file_handle *f = t->t_fh;
1697 register struct xfer *x;
1698 int errcode, fd = -1;
1699 long foptions = t->t_args->a_options;
1700 long bytesize = t->t_args->a_numbers[O_BYTESIZE];
1701 int ifexists = t->t_args->a_exists[O_IFEXISTS];
1702 int ifnexists = t->t_args->a_exists[O_IFNEXISTS];
1703 char *pathname = t->t_args->a_strings[0];
1704 char *realname = NOSTR, *dirname = NOSTR, *qfasl = FALSE;
1705 char *tempname = NOSTR;
1706 char response[CHMAXDATA + 1];
1707 off_t nbytes;
1708 struct tm *tm;
1709 struct stat sbuf;
1710
1711 log(LOG_INFO, "FILE: fileopen\n");
1712
1713 memset(&sbuf, 0, sizeof(sbuf));
1714 if ((errcode = parsepath(pathname, &dirname, &realname, 0)) != 0)
1715 goto openerr;
1716 if (foptions & ~(O_RAW|O_READ|O_WRITE|O_PROBE|O_DEFAULT|O_PRESERVE|O_BINARY|O_CHARACTER|O_PROBEDIR)) {
1717 log(LOG_ERR, "FILE:UOO: 0%O\n", foptions);
1718 errcode = ICO;
1719 goto openerr;
1720 }
1721 errcode = 0;
1722 if ((foptions & (O_READ|O_WRITE|O_PROBE)) == 0) {
1723 if (f == FNULL)
1724 foptions |= O_PROBE;
1725 else if (f->f_type == F_INPUT)
1726 foptions |= O_READ;
1727 else
1728 foptions |= O_WRITE;
1729 }
1730 switch (foptions & (O_READ|O_WRITE|O_PROBE)) {
1731 case O_READ:
1732 if (f == FNULL || f->f_type != F_INPUT) {
1733 errstring = "Bad file handle on READ";
1734 errcode = BUG;
1735 }
1736 if (ifnexists == O_XCREATE) {
1737 errstring = "IF-DOES-NOT-EXIST CREATE illegal for READ";
1738 errcode = ICO;
1739 } else if (ifnexists == O_XNONE)
1740 ifnexists = O_XERROR;
1741 ifexists = O_XNONE;
1742 break;
1743 case O_WRITE:
1744 if (f == FNULL || f->f_type != F_OUTPUT) {
1745 errstring = "Bad file handle on WRITE";
1746 errcode = BUG;
1747 } else if (ifexists == O_XNEWVERSION)
1748 errcode = UUO;
1749 else {
1750 if (ifexists == O_XNONE)
1751 ifexists = O_XSUPERSEDE;
1752 if (ifnexists == O_XNONE)
1753 ifnexists = ifexists == O_XOVERWRITE || ifexists == O_XAPPEND ? O_XERROR : O_XCREATE;
1754 }
1755 break;
1756 case O_PROBE:
1757 if (foptions & O_PROBEDIR)
1758 realname = dirname;
1759 if (f != FNULL) {
1760 errstring = "File handle supplied on PROBE";
1761 errcode = BUG;
1762 }
1763 ifnexists = O_XERROR;
1764 ifexists = O_XNONE;
1765 break;
1766 }
1767 if (errcode == 0 && f != NULL && f->f_xfer != XNULL) {
1768 errstring = "File handle in OPEN is already in use.";
1769 errcode = BUG;
1770 }
1771 if (errcode != 0)
1772 goto openerr;
1773 switch (foptions & (O_PROBE|O_READ|O_WRITE)) {
1774 case O_PROBE:
1775 if (stat(realname, &sbuf) < 0) {
1776 switch (errno) {
1777 case EACCES:
1778 errstring = SEARCHDIR;
1779 errcode = ATD;
1780 break;
1781 case ENOTDIR:
1782 errstring = PATHNOTDIR;
1783 errcode = DNF;
1784 break;
1785 case ENOENT:
1786 if (access(dirname, F_OK) != 0)
1787 errcode = DNF;
1788 else
1789 errcode = FNF;
1790 break;
1791 default:
1792 errcode = MSC;
1793 }
1794 }
1795 break;
1796 case O_WRITE:
1797 fd = 0; /* Impossible value */
1798 log(0, "stat(%s)\n", realname);
1799 if (stat(realname, &sbuf) == 0) {
1800 /*
1801 * The file exists. Disallow writing directories.
1802 * Open the real file for append, overwrite and truncate,
1803 * otherwise fall through to the file nonexistent case.
1804 */
1805 if ((sbuf.st_mode & S_IFMT) == S_IFDIR) {
1806 errstring = "File to be written is a directory";
1807 errcode = IOD;
1808 break;
1809 } else switch (ifexists) {
1810 case O_XERROR:
1811 errcode = FAE;
1812 break;
1813 case O_XTRUNCATE:
1814 fd = creat(realname, 0644);
1815 log(0, "creat(%s) fd %d\n", realname, fd);
1816 break;
1817 case O_XOVERWRITE:
1818 fd = open(realname, 1);
1819 log(0, "open(%s) fd %d\n", realname, fd);
1820 break;
1821 case O_XAPPEND:
1822 if ((fd = open(realname, 1)) > 0)
1823 lseek(fd, 0, 2);
1824 log(0, "open(%s) fd %d\n", realname, fd);
1825 break;
1826 case O_XSUPERSEDE:
1827 case O_XRENDEL:
1828 case O_XRENAME:
1829 /*
1830 * These differ only at close time.
1831 */
1832 break;
1833 }
1834 } else {
1835 log(0, "stat(%s) failed\n", realname);
1836 /*
1837 * The stat above failed. Make sure the file really doesn't
1838 * exist. Otherwise fall through to the error processing
1839 * below.
1840 */
1841 log(0, "errno %d, access() %d\n", errno, access(dirname, X_OK));
1842 log(0, "ifnexists %d, ifexists %d\n", ifnexists, ifexists);
1843
1844 if (errno != ENOENT || access(dirname, X_OK) != 0)
1845 fd = -1;
1846 else switch (ifnexists) {
1847 case O_XERROR:
1848 errcode = FNF;
1849 break;
1850 case O_XCREATE:
1851 if (ifexists == O_XAPPEND ||
1852 ifexists == O_XOVERWRITE ||
1853 ifexists == O_XTRUNCATE) {
1854 fd = creat(realname, 0644);
1855 log(0, "creat('%s') %d\n", realname, fd);
1856 }
1857 break;
1858 }
1859 }
1860 log(0, "errcode %d\n", errcode);
1861 if (errcode)
1862 break;
1863 if (fd == 0) {
1864 /*
1865 * ifexists is either SUPERSEDE, RENDEL or RENAME, so
1866 * we use temporary files.
1867 */
1868 if ((tempname = tempfile(dirname)) == NOSTR)
1869 fd = -1;
1870 else
1871 fd = creat(tempname, 0644);
1872 log(0, "create %s %d\n", tempname, fd);
1873 }
1874 /*
1875 * An error occurred either in stat, creat or open on the
1876 * realname, or on access or creat on the tempname.
1877 */
1878 if (fd < 0)
1879 switch (errno) {
1880 case EACCES:
1881 errcode = ATD;
1882 if (access(dirname, X_OK) < 0)
1883 errstring = SEARCHDIR;
1884 else if (access(dirname, W_OK) < 0)
1885 errstring = WRITEDIR;
1886 else {
1887 errcode = ATF;
1888 errstring = WRITEFILE;
1889 }
1890 break;
1891 case ENOENT:
1892 errcode = DNF;
1893 break;
1894 case ENOTDIR:
1895 errstring = PATHNOTDIR;
1896 errcode = DNF;
1897 break;
1898 case EISDIR: /* impossible */
1899 errstring = "File to be written is a directory";
1900 errcode = IOD;
1901 break;
1902 case ETXTBSY:
1903 errstring = "File to be written is being executed";
1904 errcode = LCK;
1905 break;
1906 case ENFILE:
1907 errstring = "No file descriptors available";
1908 errcode = NER;
1909 break;
1910 case ENOSPC:
1911 errstring = "No free space to create directory entry";
1912 errcode = NMR;
1913 break;
1914 default:
1915 errcode = MSC;
1916 }
1917 else if (fstat(fd, &sbuf) < 0)
1918 fatal(FSTAT);
1919 break;
1920 case O_READ:
1921 log(0, "open(%s) \n", realname);
1922 if ((fd = open(realname, 0)) < 0) {
1923 log(0, "open error\n");
1924 switch (errno) {
1925 case EACCES:
1926 if (access(dirname, X_OK) == 0) {
1927 errcode = ATF;
1928 errstring = READFILE;
1929 } else {
1930 errcode = ATD;
1931 errstring = SEARCHDIR;
1932 }
1933 break;
1934 case ENOENT:
1935 if (access(dirname, F_OK) < 0)
1936 errcode = DNF;
1937 else
1938 errcode = FNF;
1939 break;
1940 case ENOTDIR:
1941 errstring = PATHNOTDIR;
1942 errcode = DNF;
1943 break;
1944 case ENFILE:
1945 errstring = "No file descriptors available";
1946 errcode = NER;
1947 errtype = E_RECOVERABLE;
1948 break;
1949 default:
1950 errcode = MSC;
1951 }
1952 } else if (fstat(fd, &sbuf) < 0)
1953 fatal(FSTAT);
1954 else if (foptions & O_DEFAULT) {
1955 unsigned short ss[2];
1956
1957 if (read(fd, (char *)ss, sizeof(ss)) == sizeof(ss) &&
1958 ((ss[0] == QBIN1 && ss[1] == QBIN2) ||
1959 (ss[0] == LBIN1 && ss[1] < LBIN2LIMIT)))
1960 foptions |= O_BINARY;
1961 else
1962 foptions |= O_CHARACTER;
1963 (void)lseek(fd, 0L, 0);
1964 }
1965 break;
1966 }
1967 if (foptions & O_BINARY) {
1968 qfasl = TRUE;
1969 if (bytesize == 0)
1970 bytesize = 16;
1971 else if (bytesize < 0 || bytesize > 16) {
1972 errcode = IBS;
1973 }
1974 }
1975 if (errcode != 0) {
1976 if (errcode == MSC)
1977 errstring = strerror(errno);
1978 goto openerr;
1979 }
1980 tm = localtime(&sbuf.st_mtime);
1981 nbytes = foptions & O_CHARACTER || bytesize <= 8 ? sbuf.st_size : (sbuf.st_size + 1) / 2;
1982 if (protocol > 0)
1983 {
1984 #if TRUNCATE_DATES
1985 if (tm->tm_year > 99) tm->tm_year = 99;
1986 (void)sprintf(response,
1987 "%02d/%02d/%02d %02d:%02d:%02d %ld %s%s%s%c%s%c",
1988 #else
1989 if (tm->tm_year > 99) tm->tm_year += 1900;
1990 (void)sprintf(response,
1991 "%02d/%02d/%04d %02d:%02d:%02d %ld %s%s%s%c%s%c",
1992 #endif
1993 tm->tm_mon+1, tm->tm_mday, tm->tm_year,
1994 tm->tm_hour, tm->tm_min, tm->tm_sec, (long)nbytes,
1995 qfasl, foptions & O_DEFAULT ? " " : "",
1996 foptions & O_DEFAULT ? (foptions & O_CHARACTER ?
1997 TRUE : FALSE) : "",
1998 CHNL, realname, CHNL);
1999 }
2000 else
2001 {
2002 if (tm->tm_year > 99) tm->tm_year = 99;
2003 (void)sprintf(response,
2004 "%d %02d/%02d/%02d %02d:%02d:%02d %ld %s%c%s%c",
2005 -1, tm->tm_mon+1, tm->tm_mday, tm->tm_year,
2006 tm->tm_hour, tm->tm_min, tm->tm_sec, (long)nbytes,
2007 qfasl, CHNL, realname, CHNL);
2008 }
2009 if (foptions & (O_READ|O_WRITE)) {
2010 x = makexfer(t, foptions);
2011 if (x) {
2012 x->x_state = X_PROCESS;
2013 x->x_bytesize = bytesize;
2014 x->x_fd = fd;
2015 log(0, "xfer %p fd %d\n", x, fd);
2016 x->x_realname = realname;
2017 x->x_dirname = dirname;
2018 x->x_atime = sbuf.st_atime;
2019 x->x_mtime = sbuf.st_mtime;
2020 if (foptions & O_WRITE)
2021 x->x_tempname = tempname;
2022 realname = dirname = tempname = NOSTR;
2023 if ((errcode = startxfer(x)) != 0)
2024 xflush(x);
2025 }
2026 }
2027 if (errcode == 0)
2028 respond(t, response);
2029 openerr:
2030 if (errcode)
2031 error(t, f != FNULL ? f->f_name : "", errcode);
2032 if (dirname)
2033 free(dirname);
2034 if (realname)
2035 free(realname);
2036 if (tempname)
2037 free(tempname);
2038 }
2039 /*
2040 * Make up a temporary file name given a directory string.
2041 * We fail (return NOSTR) either if we can't find an unused name
2042 * (basically impossible) or if the search path is bogus.
2043 */
2044 char *
2045 tempfile(char *dname)
2046 {
2047 register char *cp = malloc((unsigned)(strlen(dname) +
2048 2 + sizeof("#FILEpppppdd")));
2049 register int i;
2050 static int lastnum;
2051
2052 if (cp == NOSTR)
2053 fatal(NOMEM);
2054 for (i = 0; i < 100; i++) {
2055 int uniq = lastnum + i;
2056
2057 if (uniq > 99)
2058 uniq -= 100;
2059 (void)sprintf(cp, "%s/#FILE%05d%02d", dname, mypid, uniq);
2060 if (access(cp, F_OK) != 0) {
2061 if (errno == ENOENT) {
2062 /*
2063 * We could be losing here if the directory doesn't exist,
2064 * but that will be caught later anyway.
2065 */
2066 lastnum = ++uniq;
2067 return cp;
2068 } else
2069 break;
2070 }
2071 }
2072 free(cp);
2073 return NOSTR; /* Our caller checks errno */
2074 }
2075
2076 void
2077 getprops(register struct transaction *t)
2078 {
2079 register struct cmdargs *a = t->t_args;
2080 register struct xfer *x;
2081 int errcode = 0;
2082 char *dirname = 0, *realname = 0, *tempname = 0;
2083 struct stat sbuf;
2084
2085 if (t->t_fh->f_xfer != XNULL) {
2086 errstring = "File handle already in use";
2087 errcode = BUG;
2088 } else if (a->a_strings[0][0]) {
2089 register struct file_handle *f;
2090
2091 for (f = file_handles; f; f = f->f_next)
2092 if (strncmp(a->a_strings[0], f->f_name, FHLEN) == 0)
2093 break;
2094 if (f == FNULL) {
2095 errcode = BUG;
2096 (void)sprintf(errstring = errbuf,
2097 "Unknown file handle: %s", a->a_strings[0]);
2098 } else if ((x = f->f_xfer) == XNULL) {
2099 errcode = BUG;
2100 (void)sprintf(errstring = errbuf,
2101 "File handle: %s has no associated file", a->a_strings[0]);
2102 } else {
2103 dirname = savestr(x->x_dirname);
2104 realname = savestr(x->x_realname);
2105 tempname = savestr(x->x_tempname);
2106 }
2107 } else
2108 errcode = parsepath(a->a_strings[1], &dirname, &realname, 0);
2109 if (errcode == 0) {
2110 if (stat(realname, &sbuf) < 0)
2111 switch (errno) {
2112 case EACCES:
2113 errstring = SEARCHDIR;
2114 errcode = ATD;
2115 break;
2116 case ENOTDIR:
2117 errstring = PATHNOTDIR;
2118 errcode = DNF;
2119 break;
2120 case ENOENT:
2121 if (access(dirname, F_OK) != 0)
2122 errcode = DNF;
2123 else
2124 errcode = FNF;
2125 break;
2126 default:
2127 errcode = MSC;
2128 }
2129 else {
2130 if (!(a->a_options & (O_BINARY | O_CHARACTER)))
2131 a->a_options |= O_CHARACTER;
2132 x = makexfer(t, a->a_options | O_PROPERTIES);
2133 if (x) {
2134 x->x_realname = realname;
2135 x->x_dirname = dirname;
2136 x->x_state = X_IDLE;
2137 x->x_tempname = tempname;
2138 if ((errcode = startxfer(x)) == 0) {
2139 t->t_command = &propcom;
2140 afree(a);
2141 t->t_args = ANULL;
2142 xcommand(t);
2143 // propopen(x, t);
2144 return;
2145 }
2146 xflush(x);
2147 }
2148 }
2149 }
2150 error(t, t->t_fh->f_name, errcode);
2151 sfree(dirname);
2152 sfree(tempname);
2153 sfree(realname);
2154 }
2155
2156 /*
2157 * Format of output is a line of changeable property names,
2158 * followed by a line of file name followed by lines
2159 * for individual properties.
2160 */
2161 void
2162 propopen(register struct xfer *x, register struct transaction *t)
2163 {
2164 register char *cp;
2165 struct stat sbuf;
2166
2167 respond(t, "");
2168 cp = x->x_bptr = x->x_bbuf;
2169 cp = getsprops(&sbuf, cp);
2170 *cp++ = '\n';
2171 strcpy(cp, x->x_realname);
2172 while (*cp)
2173 cp++;
2174 *cp++ = '\n';
2175 x->x_bptr = cp;
2176 x->x_left = x->x_bptr - x->x_bbuf;
2177 x->x_bptr = x->x_bbuf;
2178 x->x_state = X_PROCESS;
2179 return;
2180 }
2181
2182 static ssize_t
2183 propread(register struct xfer *x)
2184 {
2185 register struct property *p;
2186 register char *cp;
2187 struct stat sbuf;
2188
2189 if (x->x_realname == 0)
2190 return 0;
2191 if (stat(x->x_tempname ? x->x_tempname : x->x_realname, &sbuf) < 0)
2192 return -1;
2193 free(x->x_realname);
2194 x->x_realname = 0;
2195 cp = x->x_bbuf;
2196 for (p = properties; p->p_indicator; p++)
2197 if (!(p->p_flags & P_GLOBAL)) {
2198 register char *ep = cp;
2199 strcpy(ep, p->p_indicator);
2200 while (*ep)
2201 ep++;
2202 *ep++ = ' ';
2203 if ((ep = (*p->p_get)(&sbuf, ep))) {
2204 *ep++ = '\n';
2205 cp = ep;
2206 }
2207 }
2208 *cp++ = '\n';
2209 return cp - x->x_bbuf;
2210 }
2211 /*
2212 * Implement the directory command.
2213 * This consists of the top level command and the routines for generating
2214 * the property list of a directory entry. See chngprop and friends.
2215 */
2216 void
2217 directory(register struct transaction *t)
2218 {
2219 register struct cmdargs *a = t->t_args;
2220 register struct xfer *x;
2221 int errcode = 0;
2222 char *dirname = 0, *realname = 0;
2223
2224 if (a->a_options & ~(O_DELETED|O_FAST|O_SORTED)) {
2225 log(LOG_ERR, "FILE:UOO: 0%o\n", a->a_options);
2226 errcode = ICO;
2227 } else if (t->t_fh->f_xfer != XNULL) {
2228 errstring = "File handle already in use";
2229 errcode = BUG;
2230 } else if ((errcode = parsepath(a->a_strings[0], &dirname, &realname, 0)) == 0) {
2231 if (!(a->a_options & (O_BINARY | O_CHARACTER)))
2232 a->a_options |= O_CHARACTER;
2233 x = makexfer(t, a->a_options | O_DIRECTORY);
2234 if (x) {
2235 x->x_realname = realname;
2236 x->x_dirname = dirname;
2237 x->x_state = X_IDLE;
2238 if ((errcode = startxfer(x)) == 0) {
2239 t->t_command = &dircom;
2240 afree(t->t_args);
2241 t->t_args = ANULL;
2242 xcommand(t);
2243 // diropen(x, t);
2244 return;
2245 }
2246 xflush(x);
2247 }
2248 }
2249 error(t, t->t_fh->f_name, errcode);
2250 }
2251 /*
2252 * Start up a directory transfer by first doing the glob and responding to the
2253 * directory command.
2254 * Note that this happens as the first work in a transfer process.
2255 */
2256 void
2257 diropen(struct xfer *ax, register struct transaction *t)
2258 {
2259 register struct xfer *x = ax;
2260 struct stat *s = (struct stat *)0;
2261 struct stat sbuf;
2262 int errcode;
2263
2264 // printf("diropen: %s\n", x->x_realname);
2265
2266 x->x_glob = glob(x->x_realname);
2267 if ((errcode = globerr) != 0)
2268 goto derror;
2269
2270 if (x->x_glob) {
2271 char **badfile = NOBLK;
2272 int baderrno;
2273 /*
2274 * We still need to check for the case where the only
2275 * matching files (which don't necessarily exists) are
2276 * in non-existent directories.
2277 */
2278 for (x->x_gptr = x->x_glob; *x->x_gptr; x->x_gptr++)
2279 if (stat(*x->x_gptr, &sbuf) == 0) {
2280 s = &sbuf;
2281 break;
2282 } else if (badfile == NOBLK) {
2283 baderrno = errno;
2284 badfile = x->x_gptr;
2285 }
2286 /*
2287 * If no existing files were found, and an erroneous
2288 * file was found, scan for a file that is not simply
2289 * non-existent. If such a file is found, then we
2290 * must return an error.
2291 */
2292 if (*x->x_gptr == NOSTR && badfile != NOBLK)
2293 for (x->x_gptr = badfile; *x->x_gptr; baderrno = errno)
2294 switch(baderrno) {
2295 register char *cp;
2296 case ENOENT:
2297 cp = rindex(*x->x_gptr, '/');
2298 if (cp) {
2299 register char c;
2300
2301 c = *cp;
2302 *cp = '\0';
2303 if (access(*x->x_gptr, F_OK) < 0) {
2304 errcode = DNF;
2305 goto derror;
2306 }
2307 *cp = c;
2308 }
2309 if (*++x->x_gptr != NOSTR)
2310 access(*x->x_gptr, F_OK);
2311 break;
2312 case EACCES:
2313 errcode = ATD;
2314 errstring = SEARCHDIR;
2315 goto derror;
2316 case ENOTDIR:
2317 errcode = DNF;
2318 errstring = PATHNOTDIR;
2319 goto derror;
2320 default:
2321 errcode = MSC;
2322 errstring = strerror(baderrno);
2323 goto derror;
2324 }
2325 }
2326 {
2327 register struct property *p;
2328 register char *cp;
2329
2330 respond(t, "");
2331 /*
2332 * We create the firest record to be returned, which
2333 * is the properties of the file system as a whole.
2334 */
2335 x->x_bptr = x->x_bbuf;
2336 *x->x_bptr++ = '\n';
2337 for (p = properties; p->p_indicator; p++)
2338 if (p->p_flags & P_GLOBAL) {
2339 cp = x->x_bptr;
2340 strcpy(cp, p->p_indicator);
2341 while (*cp)
2342 cp++;
2343 *cp++ = ' ';
2344 if ((cp = (*p->p_get)(s, cp))) {
2345 *cp++ = '\n';
2346 x->x_bptr = cp;
2347 }
2348 }
2349 *x->x_bptr++ = '\n';
2350 x->x_left = x->x_bptr - x->x_bbuf;
2351 x->x_bptr = x->x_bbuf;
2352 x->x_state = X_PROCESS;
2353 #if defined(OSX)
2354 dispatch_semaphore_signal(x->x_hangsem);
2355 #else
2356 pthread_mutex_lock(&x->x_hangsem);
2357 pthread_cond_signal(&x->x_hangcond);
2358 pthread_mutex_unlock(&x->x_hangsem);
2359 #endif
2360 return;
2361 }
2362 derror:
2363 error(t, t->t_fh->f_name, errcode);
2364 x->x_state = X_DERROR;
2365 #if defined(OSX)
2366 dispatch_semaphore_signal(x->x_hangsem);
2367 #else
2368 pthread_mutex_lock(&x->x_hangsem);
2369 pthread_cond_signal(&x->x_hangcond);
2370 pthread_mutex_unlock(&x->x_hangsem);
2371 #endif
2372 }
2373 /*
2374 * Assemble a directory entry record in the buffer for this transfer.
2375 * This is actually analogous to doing a disk read on the directory
2376 * file.
2377 */
2378 static ssize_t
2379 dirread(register struct xfer *x)
2380 {
2381 struct stat sbuf;
2382
2383 if (x->x_glob == NOBLK)
2384 return 0;
2385 while (*x->x_gptr != NOSTR && stat(*x->x_gptr, &sbuf) < 0)
2386 x->x_gptr++;
2387 if (*x->x_gptr == NOSTR)
2388 return 0;
2389 (void)sprintf(x->x_bbuf, "%s\n", *x->x_gptr);
2390 x->x_gptr++;
2391 x->x_bptr = x->x_bbuf + strlen(x->x_bbuf);
2392 if (!(x->x_options & O_FAST)) {
2393 register struct property *p;
2394 register char *cp;
2395
2396 for (p = properties; p->p_indicator; p++)
2397 if (!(p->p_flags & P_GLOBAL)) {
2398 cp = x->x_bptr;
2399 strcpy(cp, p->p_indicator);
2400 while (*cp)
2401 cp++;
2402 *cp++ = ' ';
2403 if ((cp = (*p->p_get)(&sbuf, cp))) {
2404 *cp++ = '\n';
2405 x->x_bptr = cp;
2406 }
2407 }
2408 }
2409 *x->x_bptr++ = '\n';
2410 return x->x_bptr - x->x_bbuf;
2411 }
2412
2413 /*
2414 * Utilities for managing transfer tasks
2415 * Make a transfer task and initialize it;
2416 */
2417 struct xfer *
2418 makexfer(register struct transaction *t, long foptions)
2419 {
2420 register struct xfer *x;
2421
2422 x = salloc(xfer);
2423 if (x) {
2424 x->x_fh = t->t_fh;
2425 if (t->t_fh)
2426 t->t_fh->f_xfer = x;
2427 x->x_work = TNULL;
2428 x->x_flags = 0;
2429 x->x_options = foptions;
2430 if (foptions & O_WRITE)
2431 x->x_room = FSBSIZE;
2432 else
2433 x->x_room = CHMAXDATA;
2434 x->x_bptr = x->x_bbuf;
2435 x->x_pptr = x->x_pbuf;
2436 x->x_left = 0;
2437 x->x_next = xfers;
2438 x->x_realname = x->x_dirname = x->x_tempname = NOSTR;
2439 x->x_glob = (char **)0;
2440 #if defined(OSX)
2441 x->x_hangsem = dispatch_semaphore_create(0);
2442 #else
2443 pthread_mutex_init(&x->x_hangsem, NULL);
2444 pthread_cond_init(&x->x_hangcond, NULL);
2445 #endif
2446 pthread_mutex_init(&x->x_xfersem, NULL);
2447
2448 xfers = x;
2449 }
2450 else
2451 fatal(NOMEM);
2452 return x;
2453 }
2454
2455 /*
2456 * Queue up the transaction onto the transfer.
2457 */
2458 void xqueue(register struct transaction *t, register struct xfer *x)
2459 {
2460 register struct transaction **qt;
2461
2462 for (qt = &x->x_work; *qt; qt = &(*qt)->t_next)
2463 ;
2464 t->t_next = TNULL;
2465 *qt = t;
2466 }
2467
2468 /*
2469 * Issue the command on its xfer.
2470 */
2471 void
2472 xcommand(register struct transaction *t)
2473 {
2474 register struct file_handle *f;
2475 register struct xfer *x;
2476
2477 log(LOG_INFO, "FILE: transfer command: %s\n", t->t_command->c_name);
2478 if ((f = t->t_fh) == FNULL || (x = f->f_xfer) == XNULL) {
2479 errstring = "No transfer in progress on this file handle";
2480 error(t, f ? f->f_name : "", BUG);
2481 } else {
2482 xqueue(t, x);
2483 // (*t->t_command->c_func)(x, t);
2484
2485 // we may have a packet stuck waiting to transmit
2486 // force the transmit window to close and tickle the connection
2487 if ((t->t_command->c_func == fileclose || t->t_command->c_func == filepos) && x->x_options & O_READ)
2488 chaos_interrupt_connection(x->x_fh->f_connection);
2489
2490 #if defined(OSX)
2491 dispatch_semaphore_signal(x->x_hangsem);
2492 #else
2493 pthread_mutex_lock(&x->x_hangsem);
2494 pthread_cond_signal(&x->x_hangcond);
2495 pthread_mutex_unlock(&x->x_hangsem);
2496 #endif
2497 }
2498 }
2499
2500 /*
2501 * Flush the transfer - just make the file handle not busy
2502 */
2503 void
2504 xflush(register struct xfer *x)
2505 {
2506 register struct xfer **xp;
2507
2508 for (xp = &xfers; *xp && *xp != x; xp = &(*xp)->x_next)
2509 ;
2510 if (*xp == XNULL)
2511 fatal("Missing xfer");
2512 *xp = x->x_next;
2513 x->x_fh->f_xfer = XNULL;
2514 xfree(x);
2515 }
2516 /*
2517 * Free storage associated with xfer struct.
2518 */
2519 void
2520 xfree(register struct xfer *x)
2521 {
2522 register struct transaction *t;
2523
2524 while ((t = x->x_work) != TNULL) {
2525 x->x_work = t->t_next;
2526 tfree(t);
2527 }
2528
2529 if (x->x_realname)
2530 free(x->x_realname);
2531 if (x->x_tempname)
2532 free(x->x_tempname);
2533 if (x->x_dirname)
2534 free(x->x_dirname);
2535 if (x->x_glob)
2536 gfree(x->x_glob);
2537
2538 #if defined(OSX)
2539 dispatch_release(x->x_hangsem);
2540 #else
2541 pthread_mutex_destroy(&x->x_hangsem);
2542 pthread_cond_destroy(&x->x_hangcond);
2543 #endif
2544 pthread_mutex_destroy(&x->x_xfersem);
2545 sfree(x);
2546 }
2547 /*
2548 * Here are commands that operate on existing transfers. There execution
2549 * is queued and performed on the context of the transfer.
2550 * (Closing a READ or DIRECTORY transfer is special).
2551 */
2552 /*
2553 * Perform the close on the transfer.
2554 * Closing a write transfer is easy since the CLOSE command can truly
2555 * be queued. Closing a READ or DIRECTORY is harder since the transfer
2556 * is most likely blocked on writing the data into the connection and thus
2557 * will not process a queued command. Since the user side will not
2558 * drain the connection (reading until it sees a synchromous mark) until
2559 * the response to the CLOSE is received, we would deadlock unless we
2560 * interrupted the transfer task.
2561 * Basically we mark the transfer closed and make a state change if
2562 * appropriate.
2563 */
2564 void
2565 fileclose(register struct xfer *x, register struct transaction *t)
2566 {
2567 log(LOG_INFO, "FILE: fileclose\n");
2568 x->x_flags |= X_CLOSE;
2569 switch (x->x_options & (O_READ | O_WRITE | O_DIRECTORY | O_PROPERTIES)) {
2570 case O_READ:
2571 case O_DIRECTORY:
2572 case O_PROPERTIES:
2573 /*
2574 * On READing transfers we brutally force the X_DONE
2575 * state, causing the close response right away.
2576 */
2577 x->x_state = X_DONE;
2578 break;
2579 case O_WRITE:
2580 switch (x->x_state) {
2581 case X_PROCESS:
2582 case X_WSYNC:
2583 case X_RETRY:
2584 /*
2585 * Do nothing, keep going until SYNCMARK.
2586 */
2587 break;
2588 case X_ERROR:
2589 x->x_state = X_WSYNC;
2590 break;
2591 case X_BROKEN:
2592 case X_RSYNC:
2593 x->x_state = X_DONE;
2594 }
2595 }
2596 x->x_close = t;
2597 #if 0
2598 (void)signal(SIGHUP, SIG_IGN);
2599 #endif
2600
2601 #if defined(OSX)
2602 dispatch_semaphore_signal(x->x_hangsem);
2603 #else
2604 pthread_mutex_lock(&x->x_hangsem);
2605 pthread_cond_signal(&x->x_hangcond);
2606 pthread_mutex_unlock(&x->x_hangsem);
2607 #endif
2608 }
2609
2610 /*
2611 * The actual work and response to a close is called expicitly
2612 * from the transfer task when it has finished.
2613 */
2614 static void
2615 xclose(struct xfer *ax)
2616 {
2617 register struct xfer *x = ax;
2618 register struct transaction *t = x->x_close;
2619 char response[CHMAXDATA];
2620 int errcode = 0;
2621 struct tm *tm;
2622
2623 log(LOG_INFO, "FILE: xclose\n");
2624
2625 if (x->x_options & (O_DIRECTORY|O_PROPERTIES)) {
2626 respond(t, NOSTR);
2627 return;
2628 }
2629 /*
2630 * If writing a file, rename the temp file.
2631 */
2632 if (x->x_options & O_WRITE &&
2633 x->x_tempname && !(x->x_flags & X_DELETE)) {
2634 /*
2635 * We know that both names are in the same directory
2636 * and that we were already able to create the
2637 * temporary file, implying write access to the
2638 * directory at that time.
2639 */
2640 if (link(x->x_tempname, x->x_realname) == 0)
2641 (void)unlink(x->x_tempname);
2642 else switch (errno) {
2643 /* Removed out from under me! */
2644 case ENOENT:
2645 errstring = "Temporary file has disappeared";
2646 errcode = MSC;
2647 break;
2648 case EEXIST:
2649 backfile(x->x_realname);
2650 if (link(x->x_tempname, x->x_realname) == 0)
2651 (void)unlink(x->x_tempname);
2652 else {
2653 errcode = MSC;
2654 errstring = "Can't rename temporary file";
2655 }
2656 break;
2657 default:
2658 /*
2659 * Something strange has happened.
2660 */
2661 errstring = strerror(errno);
2662 errcode = MSC;
2663 break;
2664 }
2665 }
2666 if (errcode == 0) {
2667 struct stat sbuf;
2668 if (fstat(x->x_fd, &sbuf) < 0) {
2669 log(LOG_ERR, "fd:%d, pid:%d, mypid:%d, errno:%d\n", x->x_fd,
2670 getpid(), mypid, errno);
2671 fatal("Fstat in xclose 1");
2672 }
2673 if (x->x_options & O_PRESERVE ||
2674 x->x_flags & (X_ATIME|X_MTIME)) {
2675
2676 log(LOG_INFO, "xclose (3b)\n");
2677
2678 #if defined(OSX) || defined(BSD42)
2679 struct timeval timep[2];
2680
2681 timep[0].tv_sec = (x->x_options&O_PRESERVE ||
2682 x->x_flags&X_ATIME) ? x->x_atime :
2683 sbuf.st_atime;
2684 timep[1].tv_sec = (x->x_options&O_PRESERVE ||
2685 x->x_flags&X_MTIME) ? x->x_mtime :
2686 sbuf.st_mtime;
2687 /* timep[0].tv_nsec = 0; */
2688 /* timep[1].tv_nsec = 0; */
2689
2690 #else
2691 time_t timep[2];
2692
2693 timep[0] = (x->x_options&O_PRESERVE ||
2694 x->x_flags&X_ATIME) ? x->x_atime :
2695 sbuf.st_atime;
2696 timep[1] = (x->x_options&O_PRESERVE ||
2697 x->x_flags&X_MTIME) ? x->x_mtime :
2698 sbuf.st_mtime;
2699 #endif
2700 /*
2701 * No error checking is done here since CLOSE
2702 * can't really fail anyway.
2703 */
2704
2705 log(LOG_INFO, "xclose (3c)\n");
2706
2707 #if defined(OSX) || defined(BSD42) || defined(linux)
2708 if (utimes(x->x_realname, timep)) {
2709 log(LOG_INFO, "error from utimes: errno = %d %s\n", errno, strerror(errno));
2710 }
2711 #else
2712 utime(x->x_realname, timep);
2713 #endif
2714
2715 log(LOG_INFO, "xclose (3d)\n");
2716
2717 if (fstat(x->x_fd, &sbuf) < 0)
2718 fatal("Fstat in xclose 2");
2719 }
2720 tm = localtime(&sbuf.st_mtime);
2721
2722 if (protocol > 0)
2723 {
2724 #if TRUNCATE_DATES
2725 if (tm->tm_year > 99) tm->tm_year += 1900;
2726 (void)sprintf(response,
2727 #if defined(linux)
2728 "%02d/%02d/%04d %02d:%02d:%02d %ld%c%s%c",
2729 #else
2730 "%02d/%02d/%04d %02d:%02d:%02d %lld%c%s%c",
2731 #endif
2732 #else
2733 if (tm->tm_year > 99) tm->tm_year = 99;
2734 (void)sprintf(response,
2735 #if defined(linux)
2736 "%02d/%02d/%02d %02d:%02d:%02d %ld%c%s%c",
2737 #else
2738 "%02d/%02d/%02d %02d:%02d:%02d %lld%c%s%c",
2739 #endif
2740 #endif
2741
2742 tm->tm_mon+1, tm->tm_mday, tm->tm_year,
2743 tm->tm_hour, tm->tm_min, tm->tm_sec,
2744 sbuf.st_size, CHNL,
2745 x->x_realname, CHNL);
2746 }
2747 else
2748 {
2749 if (tm->tm_year > 99) tm->tm_year = 99;
2750 (void)sprintf(response,
2751 #if defined(linux)
2752 "%d %02d/%02d/%02d %02d:%02d:%02d %ld%c%s%c",
2753 #else
2754 "%d %02d/%02d/%02d %02d:%02d:%02d %lld%c%s%c",
2755 #endif
2756 -1, tm->tm_mon+1, tm->tm_mday,
2757 tm->tm_year, tm->tm_hour, tm->tm_min,
2758 tm->tm_sec, sbuf.st_size, CHNL,
2759 x->x_realname, CHNL);
2760 }
2761 respond(t, response);
2762 } else
2763 error(t, x->x_fh->f_name, errcode);
2764 log(0, "close fd %d\n", x->x_fd);
2765 (void)close(x->x_fd);
2766 }
2767 /*
2768 * Rename a file to its backup file.
2769 * If this fails, its just too bad.
2770 */
2771 void
2772 backfile(register char *file)
2773 {
2774 register char *back;
2775 #if !defined(BSD42) && !defined(linux) && !defined(OSX)
2776 register char *name = rindex(file, '/');
2777 register char *end;
2778
2779 if (name == NOSTR)
2780 name = file;
2781 else
2782 name++;
2783 #endif
2784
2785 back = malloc((unsigned)(strlen(file) + 2));
2786 if (back)
2787 {
2788 strcpy(back, file);
2789 #if !defined(BSD42) && !defined(linux) && !defined(OSX)
2790 end = name + strlen(name);
2791 if (end - name >= DIRSIZ - 1)
2792 back[name - file + DIRSIZ - 1] = '\0';
2793 #endif
2794 strcat(back, "~");
2795 /*
2796 * Get rid of the previous backup copy.
2797 * Rename current copy to backup name and if rename succeeded,
2798 * remove current copy.
2799 */
2800 (void)unlink(back);
2801 if (link(file, back) == 0)
2802 (void)unlink(file);
2803 free(back);
2804 }
2805 else
2806 fatal(NOMEM);
2807 }
2808
2809 /*
2810 * Change the file position of the file.
2811 * Transfer must be a READ and either in process or hung at EOF.
2812 */
2813 void
2814 filepos(register struct xfer *x, register struct transaction *t)
2815 {
2816 if ((x->x_options & O_READ) == 0) {
2817 errstring = "Not a reading file handle for FILEPOS";
2818 error(t, x->x_fh->f_name, BUG);
2819 } else if (!(x->x_state == X_PROCESS || x->x_state == X_REOF ||
2820 x->x_state == X_SEOF)) {
2821 errstring = "Incorrect transfer state for FILEPOS";
2822 error(t, x->x_fh->f_name, BUG);
2823 } else {
2824 off_t new = t->t_args->a_numbers[0];
2825 off_t old = tell(x->x_fd);
2826 off_t size = lseek(x->x_fd, 0L, 2);
2827
2828 /* Adjust for bytesize */
2829 new *= (x->x_bytesize == 16 ? 2 : 1);
2830
2831 if (new < 0 || new > size) {
2832 (void)lseek(x->x_fd, old, 0);
2833 errstring = "Illegal byte position for this file";
2834 error(t, x->x_fh->f_name, FOR);
2835 } else {
2836 x->x_room = CHMAXDATA;
2837 x->x_pptr = x->x_pbuf;
2838 x->x_left = 0;
2839 x->x_flags &= ~X_EOF;
2840 x->x_state = X_PROCESS;
2841 (void)lseek(x->x_fd, new, 0);
2842 respond(t, NOSTR);
2843 if (syncmark(x->x_fh) < 0)
2844 fatal("Broken data connection");
2845 if (log_verbose) {
2846 log(LOG_INFO,
2847 "pid: %ld, x: %X, fd: %ld, size: %ld, "
2848 "old: %ld, new: %ld, pos: %ld\n",
2849 getpid(), x, x->x_fd, size,
2850 old, new, tell(x->x_fd));
2851 }
2852 }
2853 }
2854 }
2855
2856 /*
2857 * Continue a transfer which is in the asynchronously marked state.
2858 */
2859 void
2860 filecontinue(register struct xfer *x, register struct transaction *t)
2861 {
2862 if (x->x_state != X_ERROR) {
2863 errstring = "CONTINUE received when not in error state.";
2864 error(t, x->x_fh->f_name, BUG);
2865 } else {
2866 x->x_state = X_RETRY;
2867 respond(t, NOSTR);
2868 }
2869 }
2870
2871 /*
2872 * Here are commands that are usually top-level but can also be
2873 * issued in reference to an existing transfer.
2874 */
2875 /*
2876 * Delete the given file.
2877 * If the delete is on a file handle, delete the file that is open.
2878 * If it open for writing and has a tempname delete the tempname, NOT the
2879 * realname.
2880 */
2881 void
2882 delete(register struct transaction *t)
2883 {
2884 register struct file_handle *f = t->t_fh;
2885 register struct xfer *x;
2886 char *file, *dir = NOSTR, *real = NOSTR, *fhname;
2887 struct stat sbuf;
2888 int errcode;
2889
2890 if (f != FNULL)
2891 if (t->t_args != ANULL && t->t_args->a_strings[0] != NOSTR) {
2892 errstring =
2893 "Both a file handle and filename in DELETE";
2894 error(t, f->f_name, BUG);
2895 } else if ((x = f->f_xfer) == XNULL) {
2896 errstring =
2897 "No transfer when DELETE on file handle";
2898 error(t, f->f_name, BUG);
2899 } else if (f->f_xfer->x_options & (O_PROPERTIES|O_DIRECTORY)) {
2900 errstring =
2901 "Trying to DELETE a directory list transfer";
2902 error(t, f->f_name, BUG);
2903 } else {
2904 fhname = f->f_name;
2905 if (unlink(x->x_tempname ? x->x_tempname : x->x_realname) < 0)
2906 goto badunlink;
2907 f->f_xfer->x_flags |= X_DELETE;
2908 respond(t, NOSTR);
2909
2910 f->f_xfer->x_flags |= X_DELETE;
2911 #if defined(OSX)
2912 dispatch_semaphore_signal(x->x_hangsem);
2913 #else
2914 pthread_mutex_lock(&x->x_hangsem);
2915 pthread_cond_signal(&x->x_hangcond);
2916 pthread_mutex_unlock(&x->x_hangsem);
2917 #endif
2918 }
2919 else if (t->t_args == ANULL ||
2920 (file = t->t_args->a_strings[0]) == NOSTR) {
2921 errstring = "No file handle or file name in DELETE";
2922 error(t, "", BUG);
2923 } else if ((errcode = parsepath(file, &dir, &real, 0)) != 0)
2924 error(t, "", errcode);
2925 else if (stat(real, &sbuf) < 0) {
2926 switch (errno) {
2927 case EACCES:
2928 errcode = ATD;
2929 errstring = SEARCHDIR;
2930 break;
2931 case ENOENT:
2932 if (access(dir, F_OK) == 0)
2933 errcode = FNF;
2934 else
2935 errcode = DNF;
2936 break;
2937 case ENOTDIR:
2938 errcode = DNF;
2939 errstring = PATHNOTDIR;
2940 break;
2941 default:
2942 errcode = MSC;
2943 errstring = strerror(errno);
2944 }
2945 error(t, "", errcode);
2946 } else if ((sbuf.st_mode & S_IFMT) == S_IFDIR) {
2947 if (access(dir, W_OK) != 0) {
2948 errstring = SEARCHDIR;
2949 error(t, "", ATD);
2950 } else if (access(real, X_OK|W_OK) != 0) {
2951 errstring =
2952 "No search or write permission on directory to be deleted.";
2953 error(t, "", ATD);
2954 } else {
2955 register int pid, rp;
2956 int st;
2957
2958 if ((pid = fork()) == 0) {
2959 (void)close(0);
2960 (void)close(1);
2961 (void)close(2);
2962 (void)open("/dev/null", 2);
2963 (void)dup(0); (void)dup(0);
2964 execl("/bin/rmdir", "rmdir", real, (char *)0);
2965 execl("/usr/bin/rmdir", "rmdir", real, (char *)0);
2966 exit(1);
2967 } else if (pid == -1) {
2968 errstring = "Can't fork subprocess for rmdir";
2969 error(t, "", NER);
2970 } else {
2971 while ((rp = wait(&st)) >= 0)
2972 if (rp == pid)
2973 break;
2974 if (rp != pid)
2975 fatal("Lost a process!");
2976 if (st != 0) {
2977 /*
2978 * We are not totally sure this is
2979 * the reason but...
2980 */
2981 errstring =
2982 "Directory to delete is not empty.";
2983 error(t, "", DNE);
2984 } else
2985 respond(t, NOSTR);
2986 }
2987 }
2988 } else if (unlink(real) < 0) {
2989 fhname = "";
2990 badunlink:
2991 switch (errno) {
2992 case EACCES:
2993 if (access(dir, X_OK) == 0)
2994 errstring = WRITEDIR;
2995 else
2996 errstring = SEARCHDIR;
2997 errcode = ATD;
2998 break;
2999 case ENOENT:
3000 if (access(dir, F_OK) == 0)
3001 errcode = FNF;
3002 else
3003 errcode = DNF;
3004 break;
3005 case ENOTDIR:
3006 errstring = PATHNOTDIR;
3007 errcode = DNF;
3008 break;
3009 default:
3010 errcode = MSC;
3011 errstring = strerror(errno);
3012 }
3013 error(t, fhname, errcode);
3014 } else
3015 respond(t, NOSTR);
3016 if (dir != NOSTR)
3017 free(dir);
3018 if (real != NOSTR)
3019 free(real);
3020 }
3021
3022 /*
3023 * Rename a file.
3024 */
3025 void
3026 xrename(register struct transaction *t)
3027 {
3028 register struct file_handle *f;
3029 register struct xfer *x;
3030 int errcode;
3031 char *file1, *file2, *dir1 = NOSTR, *dir2 = NOSTR,
3032 *real1 = NOSTR, *real2 = NOSTR;
3033
3034 file1 = t->t_args->a_strings[0];
3035 file2 = t->t_args->a_strings[1];
3036 if ((errcode = parsepath(file1, &dir1, &real1, 0)) != 0)
3037 error(t, "", errcode);
3038 else if ((f = t->t_fh) != FNULL)
3039 if (file2 != NOSTR) {
3040 errstring =
3041 "Both file handle and file name specified on RENAME";
3042 error(t, f->f_name, BUG);
3043 } else if ((x = f->f_xfer) == XNULL) {
3044 errstring = "No transfer on file handle for RENAME";
3045 error(t, f->f_name, BUG);
3046 } else if (x->x_options & (O_DIRECTORY|O_PROPERTIES)) {
3047 errstring = "Can't rename in DIRECTORY command.";
3048 error(t, f->f_name, BUG);
3049 } else {
3050 if (x->x_options & O_WRITE) {
3051 if (access(dir1, X_OK|W_OK) != 0)
3052 errcode = ATD;
3053 } else
3054 errcode = mv(x->x_realname,
3055 x->x_dirname, real1, dir1);
3056 if (errcode)
3057 error(t, f->f_name, errcode);
3058 else {
3059 free(x->x_realname);
3060 x->x_realname = real1;
3061 real1 = NOSTR;
3062 respond(t, NOSTR);
3063 #if defined(OSX)
3064 dispatch_semaphore_signal(x->x_hangsem);
3065 #else
3066 pthread_mutex_lock(&x->x_hangsem);
3067 pthread_cond_signal(&x->x_hangcond);
3068 pthread_mutex_unlock(&x->x_hangsem);
3069 #endif
3070 }
3071 }
3072 else if (file2 == NOSTR) {
3073 errstring = "Missing second filename in RENAME";
3074 error(t, "", BUG);
3075 } else if ((errcode = parsepath(file2, &dir2, &real2, 0)) != 0)
3076 error(t, "", errcode);
3077 else if ((errcode = mv(real1, dir1, real2, dir2)) != 0)
3078 error(t, "", errcode);
3079 else
3080 respond (t, NOSTR);
3081 if (dir1)
3082 free(dir1);
3083 if (dir2)
3084 free(dir2);
3085 if (real1)
3086 free(real1);
3087 if (real2)
3088 free(real2);
3089 }
3090 /*
3091 * mv, move one file to a new name (works for directory)
3092 * Second name must not exist.
3093 * Errors are returned in strings.
3094 */
3095 int
3096 mv(char *from, char *fromdir, char *to, char *todir)
3097 {
3098 struct stat sbuf;
3099 int olderrno, didstat;
3100
3101 /*
3102 * We don't want to do more system calls than necessary, but we can't
3103 * allow the super-user to unlink directories.
3104 */
3105 if (getuid() == 0) {
3106 didstat = 1;
3107 if (stat(from, &sbuf) < 0)
3108 goto fromstat;
3109 if ((sbuf.st_mode & S_IFMT) == S_IFDIR)
3110 return IOD;
3111 } else
3112 didstat = 0;
3113 if (link(from, to) == 0 && unlink(from) == 0)
3114 return 0;
3115 olderrno = errno;
3116 if (didstat == 0 && stat(from, &sbuf) < 0) {
3117 fromstat:
3118 switch (errno) {
3119 case EACCES:
3120 errstring = SEARCHDIR;
3121 return ATD;
3122 case ENOENT:
3123 return access(fromdir, F_OK) == 0 ? FNF : DNF;
3124 case ENOTDIR:
3125 errstring = PATHNOTDIR;
3126 return DNF;
3127 default:
3128 errstring = strerror(errno);
3129 return MSC;
3130 }
3131 }
3132 if ((sbuf.st_mode & S_IFMT) == S_IFDIR)
3133 return IOD;
3134 if (access(fromdir, W_OK) < 0) {
3135 errstring = "No permission to modify source directory";
3136 return ATD;
3137 }
3138 if (stat(to, &sbuf) >= 0)
3139 return REF;
3140 switch (errno) {
3141 case EACCES:
3142 errstring = SEARCHDIR;
3143 return ATD;
3144 case ENOTDIR:
3145 errstring = PATHNOTDIR;
3146 return DNF;
3147 case ENOENT:
3148 if (access(todir, F_OK) != 0)
3149 return DNF;
3150 /*
3151 * Everything looks ok. Look at the original errno.
3152 */
3153 if (olderrno == EXDEV) {
3154 errstring = "Can't rename across UNIX file systems.";
3155 return RAD;
3156 }
3157 errno = olderrno;
3158 default:
3159 errstring = strerror(errno);
3160 return MSC;
3161 }
3162 }
3163
3164 /*
3165 * File name completion.
3166 */
3167 #define SNONE 0
3168 #define SEXACT 1
3169 #define SPREFIX 2
3170 #define SMANY 3
3171 #define SDEFAULT 4
3172 #define replace(old, new) if (old) free(old); old = new ? savestr(new) : NOSTR
3173
3174 void
3175 complete(register struct transaction *t)
3176 {
3177 register char *cp, *tp;
3178 int errcode, nstate, tstate;
3179 struct stat sbuf;
3180 #if !defined(BSD42) && !defined(linux) && !defined(OSX)
3181 int dfd;
3182 #else
3183 DIR *dfd;
3184 struct direct *dirp;
3185 #endif
3186
3187 char *dfile, *ifile, *ddir, *idir, *dreal, *ireal, *dname, *iname,
3188 *dtype, *itype, *adir, *aname, *atype;
3189 union {
3190 struct direct de;
3191 char dummy[sizeof(struct direct) + 1];
3192 } d;
3193 char response[CHMAXDATA + 1];
3194
3195 if ((t->t_args->a_options & ~(O_NEWOK|O_OLD|O_DELETED|O_READ|O_WRITE))) {
3196 error(t, "", UUO);
3197 return;
3198 }
3199 d.dummy[sizeof(struct direct)] = '\0';
3200 dfile = t->t_args->a_strings[0];
3201 ifile = t->t_args->a_strings[1];
3202 adir = ddir = dreal = idir = ireal = NOSTR;
3203 aname = atype = NOSTR;
3204 iname = itype = dname = dtype = NOSTR;
3205 if (dfile[0] != '/') {
3206 errstring =
3207 "Default for completion is not an absolute pathname";
3208 error(t, "", IPS);
3209 } else if ((errcode = parsepath(dfile, &ddir, &dreal, 1)) != 0)
3210 error(t, "", errcode);
3211 else {
3212 if (ifile[0] != '/') {
3213 if ((adir = malloc((unsigned)
3214 (strlen(ddir) + strlen(ifile) + 2)))
3215 == NOSTR)
3216 fatal(NOMEM);
3217 strcpy(adir, ddir);
3218 strcat(adir, "/");
3219 strcat(adir, ifile);
3220 if ((errcode = parsepath(adir,
3221 &idir, &ireal, 1)) != 0) {
3222 error(t, "", errcode);
3223 goto freeall;
3224 }
3225 free(adir);
3226 adir = idir;
3227 idir = NOSTR;
3228 } else if ((errcode = parsepath(ifile,
3229 &adir, &ireal, 1)) != 0) {
3230 error(t, "", errcode);
3231 goto freeall;
3232 }
3233 cp = &dreal[strlen(ddir)];
3234 if (*cp == '/')
3235 cp++;
3236 if (*cp != '\0') {
3237 if ((tp = rindex(cp, '.')) == NOSTR)
3238 dname = savestr(cp);
3239 else {
3240 *tp = '\0';
3241 dname = savestr(cp);
3242 dtype = savestr(tp+1);
3243 *tp = '.';
3244 }
3245 }
3246 cp = &ireal[strlen(adir)];
3247 if (*cp == '/')
3248 cp++;
3249 if (*cp != '\0') {
3250 if ((tp = rindex(cp, '.')) == NOSTR)
3251 iname = savestr(cp);
3252 else {
3253 *tp = '\0';
3254 iname = savestr(cp);
3255 itype = savestr(tp + 1);
3256 *tp = '.';
3257 }
3258 }
3259 if (log_verbose) {
3260 log(LOG_INFO, "ifile:'%s'\nireal:'%s'\nidir:'%s'\n",
3261 ifile ? ifile : "!",
3262 ireal ? ireal : "!",
3263 idir ? idir : "!");
3264 log(LOG_INFO, "dfile:'%s'\ndreal:'%s'\nddir:'%s'\n",
3265 dfile ? dfile : "!",
3266 dreal ? dreal : "!",
3267 ddir ? ddir : "!");
3268 log(LOG_INFO, "iname:'%s'\nitype:'%s'\n",
3269 iname ? iname : "!",
3270 itype ? itype : "!");
3271 log(LOG_INFO, "dname:'%s'\ndtype:'%s'\n",
3272 dname ? dname : "!",
3273 dtype ? dtype : "!");
3274 log(LOG_INFO, "adir:'%s'\n",
3275 adir ? adir : "!");
3276 }
3277 #if !defined(BSD42) && !defined(linux) && !defined(OSX)
3278 if ((dfd = open(adir, 0)) < 0) {
3279 #else
3280 if( (dfd = opendir(adir)) == NULL ) {
3281 #endif
3282
3283 switch(errno) {
3284 case ENOENT:
3285 errcode = DNF;
3286 break;
3287 case ENOTDIR:
3288 errstring = PATHNOTDIR;
3289 errcode = DNF;
3290 break;
3291 case ENFILE:
3292 errstring = "No file descriptors available";
3293 errcode = NER;
3294 break;
3295 case EACCES:
3296 errstring = READDIR;
3297 errcode = ATD;
3298 break;
3299 default:
3300 errstring = strerror(errno);
3301 errcode = MSC;
3302 break;
3303 }
3304 error(t, "", errcode);
3305 goto freeall;
3306 }
3307
3308 nstate = tstate = SNONE;
3309 #if !defined(BSD42) && !defined(linux) && !defined(OSX)
3310 while (read(dfd, (char *)&d.de, sizeof(d.de)) == sizeof(d.de))
3311 {
3312 char *ename, *etype;
3313 int namematch, typematch;
3314
3315 if (d.de.d_ino == 0 ||
3316 (d.de.d_name[0] == '.' &&
3317 (d.de.d_name[1] == '\0' ||
3318 (d.de.d_name[1] == '.' && d.de.d_name[2] == '\0'))))
3319 continue;
3320 ename = d.de.d_name;
3321 #else
3322 while( (dirp = readdir(dfd)) != NULL ) {
3323 char *ename, *etype;
3324 int namematch, typematch;
3325
3326 if (log_verbose) {
3327 log(LOG_INFO, "top of readdir loop; '%s'\n",
3328 dirp->d_name);
3329 }
3330
3331 if (dirp->d_ino == 0 ||
3332 (dirp->d_name[0] == '.' &&
3333 (dirp->d_name[1] == '\0' ||
3334 (dirp->d_name[1] == '.' && dirp->d_name[2] == '\0'))))
3335 continue;
3336 ename = dirp->d_name;
3337 #endif
3338 if ((etype = rindex(ename, '.')) != NOSTR)
3339 *etype++ = '\0';
3340 if ((namematch = prefix(iname, ename)) == SNONE ||
3341 (typematch = prefix(itype, etype)) == SNONE)
3342 continue;
3343 if (log_verbose) {
3344 log(LOG_INFO, "ename:'%s' etype:'%s'\n",
3345 ename ? ename : "!",
3346 etype ? etype : "!");
3347 log(LOG_INFO, "nm:%d, tm:%d, ns:%d, ts:%d\n",
3348 namematch, typematch, nstate, tstate);
3349 }
3350 if (namematch == SEXACT) {
3351 if (typematch == SEXACT) {
3352 nstate = tstate = SEXACT;
3353 goto gotit;
3354 }
3355 if (dtype && strcmp(etype, dtype) == 0)
3356 tstate = SDEFAULT;
3357 else if (nstate != SEXACT) {
3358 replace(atype, etype);
3359 tstate = SPREFIX;
3360 } else if (tstate != SDEFAULT) {
3361 tstate = SMANY;
3362 incommon(atype, etype);
3363 }
3364 nstate = SEXACT;
3365 } else if (nstate == SNONE) {
3366 nstate = SPREFIX;
3367 replace(aname, ename);
3368 if (typematch == SEXACT && iname != NOSTR)
3369 tstate = SEXACT;
3370 else if (dtype && strcmp(etype, dtype) == 0)
3371 tstate = SDEFAULT;
3372 else {
3373 replace(atype, etype);
3374 tstate = SPREFIX;
3375 }
3376 } else if (tstate == SEXACT) {
3377 if (typematch == SEXACT) {
3378 nstate = SMANY;
3379 incommon(aname, ename);
3380 }
3381 } else if (typematch == SEXACT && iname != NOSTR) {
3382 replace(aname, ename);
3383 tstate = SEXACT;
3384 nstate = SPREFIX;
3385 } else if (dtype && etype && strcmp(etype, dtype) == 0) {
3386 if (tstate == SDEFAULT) {
3387 incommon(aname, ename);
3388 nstate = SMANY;
3389 } else {
3390 replace(aname, ename);
3391 tstate = SDEFAULT;
3392 nstate = SPREFIX;
3393 }
3394 } else if (tstate != SDEFAULT) {
3395 if (nstate == SPREFIX) {
3396 if (tstate != SDEFAULT) {
3397 incommon(aname, ename);
3398 incommon(atype, etype);
3399 tstate = nstate = SMANY;
3400 }
3401 } else if (nstate == SMANY) {
3402 tstate = SMANY;
3403 incommon(atype, etype);
3404 }
3405 }
3406 if (log_verbose) {
3407 log(LOG_INFO, "aname:'%s', atype:'%s'\n",
3408 aname ? aname : "!",
3409 atype ? atype : "!");
3410 log(LOG_INFO, "nstate: %d, tstate: %d\n",
3411 nstate, tstate);
3412 }
3413 }
3414 gotit:
3415 #if !defined(BSD42) && !defined(linux) && !defined(OSX)
3416 (void)close(dfd);
3417 #else
3418 closedir(dfd);
3419 #endif
3420 if (tstate != SEXACT && tstate != SNONE) {
3421 if (itype) free(itype);
3422 if (tstate == SDEFAULT) {
3423 itype = dtype;
3424 dtype = NOSTR;
3425 } else {
3426 itype = atype;
3427 atype = NOSTR;
3428 }
3429 }
3430 if (nstate != SEXACT && nstate != SNONE) {
3431 if (iname) free(iname);
3432 iname = aname;
3433 aname = NOSTR;
3434 }
3435 (void)sprintf(errbuf, "%s%s%s%s%s",
3436 adir ? adir : "", adir && adir[1] != '\0' ? "/" : "",
3437 iname ? iname : "", itype ? "." : "",
3438 itype ? itype : "");
3439 if ((nstate == SEXACT || nstate == SPREFIX) &&
3440 (tstate == SEXACT || tstate == SPREFIX) &&
3441 stat(errbuf, &sbuf) == 0 &&
3442 (sbuf.st_mode & S_IFMT) == S_IFDIR)
3443 strcat(errbuf, "/");
3444 sprintf(response, "%s%c%s%c",
3445 nstate == SNONE || nstate == SMANY || tstate == SMANY ?
3446 "NIL" : "OLD",
3447 CHNL, errbuf, CHNL);
3448 respond(t, response);
3449 }
3450 freeall:
3451 if (iname) free(iname);
3452 if (itype) free(itype);
3453 if (dname) free(dname);
3454 if (dtype) free(dtype);
3455 if (aname) free(aname);
3456 if (atype) free(atype);
3457 if (adir) free(adir);
3458 if (ireal) free(ireal);
3459 if (dreal) free(dreal);
3460 if (idir) free(idir);
3461 if (ddir) free(ddir);
3462 }
3463
3464 void
3465 incommon(register char *old, register char *new)
3466 {
3467 if (old != NOSTR && new != NOSTR) {
3468 while (*old && *new++ == *old)
3469 old++;
3470 *old = 0;
3471 }
3472 }
3473
3474 int
3475 prefix(register char *in, register char *new)
3476 {
3477 if (in == NOSTR)
3478 return new == NOSTR ? SEXACT : SPREFIX;
3479 if (new == NOSTR)
3480 return SNONE;
3481 while (*in == *new++)
3482 if (*in++ == '\0')
3483 return SEXACT;
3484 return *in == '\0' ? SPREFIX : SNONE;
3485 }
3486
3487 /*
3488 * Create a directory
3489 */
3490 void
3491 crdir(register struct transaction *t)
3492 {
3493 char *dir = NULL, *file = NULL, *parent = NULL;
3494 int errcode;
3495 struct stat sbuf;
3496
3497 if ((errcode = parsepath(t->t_args->a_strings[0], &dir, &file, 1)))
3498 error(t, "", errcode);
3499 else {
3500 free(file);
3501 file = NULL;
3502 if ((errcode = parsepath(dir, &parent, &file, 0)))
3503 error(t, "", errcode);
3504 else if (access(parent, X_OK|W_OK) != 0) {
3505 if (errno == EACCES) {
3506 errcode = ATD;
3507 errstring =
3508 "Permission denied on parent directory.";
3509 } else {
3510 errcode = DNF;
3511 errstring = "Parent directory doesn't exist.";
3512 }
3513 error(t, "", errcode);
3514 } else if (stat(dir, &sbuf) >= 0) {
3515 if ((sbuf.st_mode & S_IFMT) == S_IFDIR) {
3516 errcode = DAE;
3517 errstring = "Directory already exists." ;
3518 } else {
3519 errcode = DAE;
3520 errstring =
3521 "File already exists with same name.";
3522 }
3523 error(t, "", errcode);
3524 } else {
3525 register int pid, rp;
3526 int st;
3527
3528 if ((pid = fork()) == 0) {
3529 (void)close(0);
3530 (void)close(1);
3531 (void)close(2);
3532 (void)open("/dev/null", 2);
3533 (void)dup(0); (void)dup(0);
3534 execl("/bin/mkdir", "mkdir", dir, (char *)0);
3535 execl("/usr/bin/mkdir", "mkdir", dir, (char *)0);
3536 exit(1);
3537 }
3538 while ((rp = wait(&st)) >= 0)
3539 if (rp == pid)
3540 break;
3541 if (rp != pid)
3542 fatal("Lost a process!");
3543 if (st != 0) {
3544 errstring = "UNIX mkdir failed.";
3545 error(t, "", MSC);
3546 } else
3547 respond(t, NOSTR);
3548 }
3549 }
3550 if (file)
3551 free(file);
3552 if (dir)
3553 free(dir);
3554 if (parent)
3555 free(parent);
3556 }
3557
3558 /*
3559 * Expunge directory. This is rather easy on UNIX.
3560 */
3561 void
3562 expunge(register struct transaction *t)
3563 {
3564 char *dir = NULL, *file = NULL;
3565 int errcode;
3566
3567 if ((errcode = parsepath(t->t_args->a_strings[0], &dir, &file, 1)))
3568 error(t, "", errcode);
3569 else {
3570 free(file);
3571 free(dir);
3572 respond(t, "0");
3573 }
3574 }
3575
3576 /*
3577 * Change properties. Either of a file or the file on a tranfer.
3578 */
3579 void
3580 chngprop(register struct transaction *t)
3581 {
3582 register struct file_handle *f = t->t_fh;
3583 register struct xfer *x = XNULL;
3584 int errcode;
3585 char *file = 0, *dir = 0, *fhname;
3586 struct stat sbuf;
3587
3588 if (f != FNULL) {
3589 fhname = f->f_name;
3590 if (t->t_args != ANULL && t->t_args->a_strings[0] != NOSTR &&
3591 t->t_args->a_strings[0][0] != '\0') {
3592 errstring =
3593 "Both file handle and file name in CHANGE-PROPERTIES";
3594 error(t, fhname, BUG);
3595 } else if ((x = f->f_xfer) == XNULL) {
3596 errstring =
3597 "No transfer on file handle for CHANGE-PROPERTIES";
3598 error(t, fhname, BUG);
3599 } else if (f->f_xfer->x_options & (O_PROPERTIES|O_DIRECTORY)) {
3600 errstring = "CHANGE-PROPERTIES on directory transfer";
3601 error(t, fhname, BUG);
3602 } else {
3603 file = x->x_options & O_WRITE ? x->x_tempname : x->x_realname;
3604 if (stat(file, &sbuf) < 0)
3605 fatal(FSTAT);
3606 goto doit;
3607 }
3608 } else
3609 fhname = "";
3610 if ((errcode = parsepath(t->t_args->a_strings[0], &dir, &file, 0)))
3611 error(t, fhname, errcode);
3612 else if (stat(file, &sbuf) < 0) {
3613 switch (errno) {
3614 case EACCES:
3615 errcode = ATD;
3616 errstring = SEARCHDIR;
3617 break;
3618 case ENOENT:
3619 if (access(dir, F_OK) == 0)
3620 errcode = FNF;
3621 else
3622 errcode = DNF;
3623 break;
3624 case ENOTDIR:
3625 errcode = DNF;
3626 errstring = PATHNOTDIR;
3627 break;
3628 default:
3629 errcode = MSC;
3630 errstring = strerror(errno);
3631 }
3632 error(t, fhname, errcode);
3633 } else {
3634 register struct property *pp;
3635 register struct plist *plp;
3636 doit:
3637 for (plp = t->t_args->a_plist; plp; plp = plp->p_next) {
3638 for (pp = properties; pp->p_indicator; pp++)
3639 if (strcmp(pp->p_indicator, plp->p_name) == 0) {
3640 if (pp->p_put)
3641 if ((errcode = (*pp->p_put)(&sbuf, file, plp->p_value, x))) {
3642 error(t, fhname, errcode);
3643 return;
3644 } else
3645 break;
3646 else {
3647 errstring = errbuf;
3648 (void)sprintf(errstring,
3649 "No a changeable property: %s",
3650 plp->p_name);
3651 error(t, fhname, CSP);
3652 return;
3653 }
3654 }
3655 if (pp->p_indicator == NOSTR) {
3656 (void)sprintf(errbuf,
3657 "Unknown property name: %s",
3658 plp->p_name);
3659 errstring = errbuf;
3660 error(t, fhname, UKP);
3661 return;
3662 }
3663 }
3664 respond(t, NOSTR);
3665 }
3666 }
3667
3668 /*
3669 * Property routines - one to get each property gettable by the DIRECTORY
3670 * command and one to put each property changeable by the change properties
3671 * command.
3672 */
3673 char *
3674 getdev(register struct stat *s, register char *cp)
3675 {
3676 (void)sprintf(cp, "%o", s->st_dev);
3677 while (*cp)
3678 cp++;
3679 return cp;
3680 }
3681
3682 /* ARGSUSED */
3683 char *
3684 getblock(struct stat *s, char *cp)
3685 {
3686 (void)sprintf(cp, "%d", FSBSIZE);
3687 while (*cp)
3688 cp++;
3689 return cp;
3690 }
3691
3692 char *
3693 getspace(struct stat *s, char *cp)
3694 {
3695 off_t total;
3696 off_t free;
3697 off_t used;
3698 int fd;
3699 ssize_t len;
3700 struct stat mstbuf;
3701 #ifdef __NetBSD__
3702 struct statvfs sblock;
3703 #else
3704 struct statfs sblock;
3705 #endif
3706 struct mtab {
3707 char path[32];
3708 char spec[32];
3709 } mtab;
3710 char dev[32 + sizeof("/dev/")];
3711
3712 if (!s)
3713 return 0;
3714 if ((fd = open("/etc/mtab", 0)) < 0)
3715 return 0;
3716 while((len = read(fd, (char *)&mtab, sizeof(mtab))) == sizeof(mtab)) {
3717 strcpy(dev, "/dev/");
3718 strcat(dev, mtab.spec);
3719 if (stat(dev, &mstbuf) == 0 &&
3720 mstbuf.st_rdev == s->st_dev) {
3721 break;
3722 }
3723 }
3724 (void)close(fd);
3725 if(len != sizeof(mtab))
3726 return 0;
3727
3728 #ifdef __NetBSD__
3729 if (statvfs(mtab.path, &sblock) == -1)
3730 return 0;
3731 #else
3732 if (statfs(dev, &sblock))
3733 return 0;
3734 #endif
3735 total = (off_t)(sblock.f_bsize * (sblock.f_blocks - sblock.f_bfree));
3736 free = (off_t)(sblock.f_bsize * sblock.f_bfree);
3737 used = total - free;
3738
3739 (void)
3740 #if defined(linux)
3741 sprintf(cp, "%s (%s): %ld free, %ld/%ld used (%ld%%)", mtab.path, mtab.spec,
3742 #else
3743 sprintf(cp, "%s (%s): %lld free, %lld/%lld used (%lld%%)", mtab.path, mtab.spec,
3744 #endif
3745 free, used, total, (100L * used + total / 2) / total);
3746 while (*cp)
3747 cp++;
3748 return cp;
3749 }
3750 /*
3751 * We don't account for indirect blocks...
3752 */
3753 static char *
3754 xgetbsize(struct stat *s, char *cp)
3755 {
3756 #if defined(linux)
3757 (void)sprintf(cp, "%ld", (s->st_size + FSBSIZE - 1) / FSBSIZE);
3758 #else
3759 (void)sprintf(cp, "%lld", (s->st_size + FSBSIZE - 1) / FSBSIZE);
3760 #endif
3761
3762 while (*cp)
3763 cp++;
3764 return cp;
3765 }
3766
3767 /* ARGSUSED */
3768 char *
3769 getbyte(struct stat *s, char *cp)
3770 {
3771 *cp++ = '8';
3772 *cp = '\0';
3773 return cp;
3774 }
3775
3776 char *
3777 getsize(register struct stat *s, register char *cp)
3778 {
3779 #if defined(linux)
3780 (void)sprintf(cp, "%ld", s->st_size);
3781 #else
3782 (void)sprintf(cp, "%lld", s->st_size);
3783 #endif
3784 while (*cp)
3785 cp++;
3786 return cp;
3787 }
3788
3789 char *
3790 getmdate(register struct stat *s, register char *cp)
3791 {
3792 struct tm *tm;
3793
3794 tm = localtime(&s->st_mtime);
3795 #if TRUNCATE_DATES
3796 if (tm->tm_year > 99) tm->tm_year = 99;
3797 (void)sprintf(cp, "%02d/%02d/%02d %02d:%02d:%02d",
3798 #else
3799 if (tm->tm_year > 99) tm->tm_year += 1900;
3800 (void)sprintf(cp, "%02d/%02d/%04d %02d:%02d:%02d",
3801 #endif
3802 tm->tm_mon+1, tm->tm_mday, tm->tm_year,
3803 tm->tm_hour, tm->tm_min, tm->tm_sec);
3804 while (*cp)
3805 cp++;
3806 return cp;
3807 }
3808
3809 char *
3810 getrdate(register struct stat *s, register char *cp)
3811 {
3812 struct tm *tm;
3813
3814 tm = localtime(&s->st_atime);
3815 #if TRUNCATE_DATES
3816 if (tm->tm_year > 99) tm->tm_year = 99;
3817 (void)sprintf(cp, "%02d/%02d/%02d %02d:%02d:%02d",
3818 #else
3819 if (tm->tm_year > 99) tm->tm_year += 1900;
3820 (void)sprintf(cp, "%02d/%02d/%04d %02d:%02d:%02d",
3821 #endif
3822 tm->tm_mon+1, tm->tm_mday, tm->tm_year,
3823 tm->tm_hour, tm->tm_min, tm->tm_sec);
3824 while (*cp)
3825 cp++;
3826 return cp;
3827 }
3828 /*
3829 char *
3830 getcdate(s, cp)
3831 register struct stat *s;
3832 register char *cp;
3833 {
3834 struct tm *tm;
3835
3836 tm = localtime(&s->st_mtime);
3837 (void)sprintf(cp, "%02d/%02d/%02d %02d:%02d:%02d",
3838 tm->tm_mon+1, tm->tm_mday, tm->tm_year,
3839 tm->tm_hour, tm->tm_min, tm->tm_sec);
3840 while (*cp)
3841 cp++;
3842 return cp;
3843 }
3844 */
3845
3846 char *
3847 getdir(register struct stat *s, register char *cp)
3848 {
3849 if ((s->st_mode & S_IFMT) == S_IFDIR) {
3850 *cp++ = 'T';
3851 *cp = '\0';
3852 return cp;
3853 } else
3854 return 0;
3855 }
3856
3857 char *
3858 getname(register struct stat *s, register char *cp)
3859 {
3860 register struct passwd *pw;
3861
3862 if ((pw = getpwuid(s->st_uid)))
3863 (void) sprintf(cp, "%s", pw->pw_name);
3864 else
3865 (void) sprintf(cp, "#%d", s->st_uid);
3866 while (*cp)
3867 cp++;
3868 return cp;
3869 }
3870
3871 char *
3872 getprot(register struct stat *s, register char *cp)
3873 {
3874 (void)sprintf(cp, "0%o", s->st_mode & 07777);
3875 while (*cp)
3876 cp++;
3877 return cp;
3878 }
3879
3880 /* ARGSUSED */
3881 char *
3882 getsprops(struct stat *s, register char *cp)
3883 {
3884 register struct property *pp;
3885 register char *p;
3886
3887 for (p = cp, pp = properties; pp->p_indicator; pp++)
3888 if (pp->p_put) {
3889 if (p != cp)
3890 *p++ = ' ';
3891 strcpy(p, pp->p_indicator);
3892 while (*p)
3893 p++;
3894 }
3895 if (p != cp && p[-1] == ' ')
3896 p--;
3897 *p = '\0';
3898 return p;
3899 }
3900
3901 int
3902 putprot(register struct stat *s, char *file, char *newprot)
3903 {
3904 register char *cp;
3905 mode_t mode;
3906
3907 for (mode = 0, cp = newprot; *cp; cp++)
3908 if (*cp < '0' || *cp > '7') {
3909 (void)
3910 sprintf(errstring = errbuf,
3911 "Illegal protection mode, must be octal: %s",
3912 newprot);
3913 return IPV;
3914 } else {
3915 mode <<= 3;
3916 mode |= *cp & 7;
3917 }
3918 if (mode > 07777 || mode < 0) {
3919 (void)sprintf(errstring = errbuf,
3920 "Illegal protection mode, must be octal: %s",
3921 newprot);
3922 return IPV;
3923 }
3924 if (mode != (s->st_mode & 07777) && chmod(file, mode) < 0) {
3925 errstring = "No permission to change protection modes";
3926 return ATF;
3927 }
3928 return 0;
3929 }
3930
3931 int
3932 putname(register struct stat *s, char *file, char *newname)
3933 {
3934 register struct passwd *pw;
3935
3936 if ((pw = getpwnam(downcase(newname))) == NULL) {
3937 (void)sprintf(errstring = errbuf, "Unknown user name: %s",
3938 newname);
3939 return IPV;
3940 } else if (s->st_uid != pw->pw_uid &&
3941 chown(file, pw->pw_uid, s->st_gid) < 0) {
3942 errstring = "No permission to change author";
3943 return ATF;
3944 }
3945 return 0;
3946 }
3947
3948 /*
3949 * This should be deferred until close time.
3950 * Actually it should be done twice - now and at close time.
3951 */
3952 int
3953 putmdate(register struct stat *s, char *file, char *newtime, register struct xfer *x)
3954 {
3955 time_t mtime;
3956
3957 if (parsetime(newtime, &mtime)) {
3958 errstring = "Illegal modification date format";
3959 return IPV;
3960 }
3961 if (mtime != s->st_mtime) {
3962 struct utimbuf timep;
3963
3964 timep.actime = s->st_atime;
3965 timep.modtime = mtime;
3966 if (utime(file, &timep) < 0) {
3967 errstring =
3968 "No permission to change modification time";
3969 return ATF;
3970 } else if (x) {
3971 x->x_mtime = mtime;
3972 x->x_flags |= X_MTIME;
3973 #if defined(OSX)
3974 dispatch_semaphore_signal(x->x_hangsem);
3975 #else
3976 pthread_mutex_lock(&x->x_hangsem);
3977 pthread_cond_signal(&x->x_hangcond);
3978 pthread_mutex_unlock(&x->x_hangsem);
3979 #endif
3980 }
3981 }
3982 return 0;
3983 }
3984
3985 int
3986 putrdate(register struct stat *s, char *file, char *newtime, register struct xfer *x)
3987 {
3988 time_t atime;
3989
3990 if (parsetime(newtime, &atime)) {
3991 errstring = "Illegal reference date format";
3992 return IPV;
3993 }
3994 if (atime != s->st_atime) {
3995 struct utimbuf timep;
3996
3997 timep.modtime = s->st_mtime;
3998 timep.actime = atime;
3999 if (utime(file, &timep) < 0) {
4000 errstring = "No permission to change reference date";
4001 return ATF;
4002 } else if (x) {
4003 x->x_mtime = atime;
4004 x->x_flags |= X_ATIME;
4005 #if defined(OSX)
4006 dispatch_semaphore_signal(x->x_hangsem);
4007 #else
4008 pthread_mutex_lock(&x->x_hangsem);
4009 pthread_cond_signal(&x->x_hangcond);
4010 pthread_mutex_unlock(&x->x_hangsem);
4011 #endif
4012 }
4013 }
4014 return 0;
4015 }
4016
4017 static int dmsize[12] =
4018 {
4019 31,
4020 28,
4021 31,
4022 30,
4023 31,
4024 30,
4025 31,
4026 31,
4027 30,
4028 31,
4029 30,
4030 31
4031 };
4032
4033 int
4034 parsetime(register char *cp, register time_t *t)
4035 {
4036 register int i;
4037 int month, day, year, hour, minute, second;
4038
4039 if (!(cp = tnum(cp, '/', &month)) ||
4040 !(cp = tnum(cp, '/', &day)) ||
4041 !(cp = tnum(cp, ' ', &year)) ||
4042 !(cp = tnum(cp, ':', &hour)) ||
4043 !(cp = tnum(cp, ':', &minute)) ||
4044 !(cp = tnum(cp, '\0', &second)) ||
4045 month < 1 || month > 12 ||
4046 day < 1 || day > 31 ||
4047 year < 70 || // year > 99 ||
4048 hour < 0 || hour > 23 ||
4049 minute < 0 || minute > 59 ||
4050 second < 0 || second > 59)
4051 return 1;
4052 if (year < 100)
4053 year += 1900;
4054 *t = 0;
4055 #define dysize(i) (((i%4)==0) ? 366 : 365)
4056 for (i = 1970; i < year; i++)
4057 *t += dysize(i);
4058 if (dysize(year) == 366 && month >= 3)
4059 (*t)++;
4060 while (--month)
4061 *t += dmsize[month - 1];
4062 *t += day - 1;
4063 *t *= 24;
4064 *t += hour;
4065 *t *= 60;
4066 *t += minute;
4067 *t *= 60;
4068 *t += second;
4069 /*
4070 * Now convert to GMT
4071 */
4072 *t += (long)timeinfo.timezone * 60;
4073 if(localtime(t)->tm_isdst)
4074 *t -= 60*60;
4075 return 0;
4076 }
4077
4078 char *
4079 tnum(register char *cp, char delim, int *ip)
4080 {
4081 register int i;
4082
4083 if (isdigit(*cp)) {
4084 i = *cp - '0';
4085 if (isdigit(*++cp)) {
4086 i *= 10;
4087 i += *cp - '0';
4088 cp++;
4089 }
4090 if (*cp == delim) {
4091 *ip = i;
4092 return ++cp;
4093 }
4094 }
4095 return 0;
4096 }
4097
4098
4099 static void
4100 jamlower(char *s)
4101 {
4102 size_t i;
4103 size_t l;
4104
4105 if (s == 0) return;
4106 if (s[0] == 0) return;
4107 l = strlen(s);
4108 for (i = 0; i < l; i++)
4109 s[i] = (char)tolower(s[i]);
4110 }
4111
4112 /*
4113 * Parse the pathname into directory and full name parts.
4114 * Returns text messages if anything is wrong.
4115 * Checking is done for well-formed pathnames, .. components,
4116 * and leading tildes. Wild carding is not done here. Should it?
4117 */
4118 int
4119 parsepath(register char *path, char **dir, char **real, int blankok)
4120 {
4121 register char *cp;
4122 int errcode;
4123 char *wd, save;
4124 int freewd = 0;
4125
4126 if (path == 0) {
4127 errstring = "Empty pathname";
4128 return IPS;
4129 }
4130 if (*path == '~') {
4131 for (cp = path; *cp != '\0' && *cp != '/'; cp++)
4132 ;
4133 if (cp == path + 1) {
4134 if ((wd = home) == NOSTR) {
4135 errstring = "Can't expand '~', not logged in.";
4136 return NLI;
4137 }
4138 } else {
4139 struct passwd *pw;
4140
4141 save = *cp;
4142 *cp = '\0';
4143 if ((pw = getpwnam(path+1)) == NULL) {
4144 *cp = save;
4145 (void)sprintf(errstring = errbuf,
4146 "Unknown user name: %s after '~'.",
4147 path+1);
4148 return IPS; /* Invalid pathname syntax */
4149 }
4150 *cp = save;
4151 wd = pw->pw_dir;
4152 }
4153 path = cp;
4154 while (*path == '/')
4155 path++;
4156 } else if (*path == '/')
4157 {
4158 #if defined(MAP_SITE_TREE_DIRECTORY)
4159 if (treeroot == NULL || path[0] != '/' || tolower(path[1]) != 't' || tolower(path[2]) != 'r' ||
4160 tolower(path[3]) != 'e' || tolower(path[4]) != 'e' || (path[5] != '/' && path[5] != '\0'))
4161 wd = "";
4162 else
4163 {
4164 size_t newlength = strlen(treeroot) + strlen(path);
4165
4166 wd = malloc(newlength);
4167 strcpy(wd, treeroot);
4168 path += 6;
4169 freewd = 1;
4170 }
4171 #else // !MAP_SITE_TREE_DIRECTORY
4172 wd = "";
4173 #endif
4174 }
4175 else if ((wd = cwd) == NOSTR) {
4176 errstring = "Relative pathname when no working directory";
4177 return IPS;
4178 }
4179 cp = malloc((unsigned)(strlen(wd) + strlen(path) + 2));
4180 if (cp) {
4181 strcpy(cp, wd);
4182 if (wd[0] != '\0')
4183 (void)strcat(cp, "/");
4184 (void)strcat(cp, path);
4185 if ((errcode = dcanon(cp, blankok))) {
4186 if (freewd)
4187 free(wd);
4188 (void)free(cp);
4189 return errcode;
4190 }
4191 *real = cp;
4192 jamlower(*real);
4193 }
4194 else
4195 fatal(NOMEM);
4196
4197 cp = rindex(cp, '/');
4198 if (cp) {
4199 if (cp == *real)
4200 cp++;
4201 save = *cp;
4202 *cp = '\0';
4203 *dir = savestr(*real);
4204 jamlower(*dir);
4205 *cp = save;
4206 }
4207 else
4208 fatal("Parsepath");
4209
4210 if (freewd)
4211 free(wd);
4212 return 0;
4213 }
4214
4215 /*
4216 * dcanon - canonicalize the pathname, removing excess ./ and ../ etc.
4217 * we are of course assuming that the file system is standardly
4218 * constructed (always have ..'s, directories have links)
4219 * Stolen from csh (My old code).
4220 */
4221 int
4222 dcanon(char *cp, int blankok)
4223 {
4224 register char *p, *sp;
4225 register int slash;
4226
4227 if (*cp != '/')
4228 return 0;
4229 for (p = cp; *p; ) { /* for each component */
4230 sp = p; /* save slash address */
4231 while(*++p == '/') /* flush extra slashes */
4232 ;
4233 if (p != ++sp)
4234 strcpy(sp, p);
4235 p = sp; /* save start of component */
4236 if (*sp == '\0') { /* if component is null */
4237 if (--sp != cp) { /* if path is not one char (i.e. /) */
4238 if (blankok)
4239 break;
4240 else
4241 return IPS;
4242 }
4243 break;
4244 }
4245 slash = 0;
4246 if (*p) while(*++p) /* find next slash or end of path */
4247 if (*p == '/') {
4248 slash = 1;
4249 *p = 0;
4250 break;
4251 }
4252 /* Can't do this now since we also parse {foo,abc,xyz}
4253 if (p - sp > DIRSIZ) {
4254 (void)sprintf(errstring = errbuf,
4255 "Pathname component: '%s', longer than %d characters",
4256 sp, DIRSIZ);
4257 return IPS;
4258 }
4259 */
4260 if (sp[0] == '.' && sp[1] == '\0') {
4261 if (slash) {
4262 strcpy(sp, ++p);
4263 p = --sp;
4264 }
4265 } else if (sp[0] == '.' && sp[1] == '.' && sp[2] == '\0') {
4266 if (--sp != cp)
4267 while (*--sp != '/')
4268 ;
4269 if (slash) {
4270 strcpy(++sp, ++p);
4271 p = --sp;
4272 } else if (cp == sp)
4273 *++sp = '\0';
4274 else
4275 *sp = '\0';
4276 } else if (slash)
4277 *p = '/';
4278 }
4279 return 0;
4280 }
4281
4282 /*
4283 * File handle error routine.
4284 */
4285 static int
4286 fherror(register struct file_handle *f, int code, int type, char *message)
4287 {
4288 register struct file_error *e = &errors[code];
4289 struct chpacket packet;
4290
4291 packet.cp_op = ASYNOP;
4292 (void)sprintf(packet.cp_data, "TIDNO %s ERROR %s %c %s",
4293 f->f_name, e->e_code, type, message ? message : e->e_string);
4294
4295 chaos_packet *error = chaos_allocate_packet(f->f_connection, packet.cp_op, (int)strlen(packet.cp_data));
4296
4297 memcpy(error->data, packet.cp_data, strlen(packet.cp_data));
4298
4299 chaos_connection_queue(f->f_connection, error);
4300
4301 return 0;
4302 }
4303
4304
4305 /*
4306 * Function to perform a unit of work on a transfer.
4307 * The point here is to do exactly one network operation.
4308 * Multiple disk/file operations can be performed.
4309 * If the transfer should be discarded completely, X_FLUSH
4310 * is returned. If the transfer must have further commands
4311 * to continue, X_HANG is returned. X_CONTINUE is returned if the
4312 * transfer is happy to continue what it is doing.
4313 *
4314 * Transfers go through several states, which differ greatly depending
4315 * on the direction of transfer.
4316 *
4317 * READ (disk to net) transfers:
4318 * 1. X_PROCESS Initial state and data transfer state until:
4319 * Normally - DATA packet sent: stay in X_PROCESS
4320 * - EOF read from disk, last data sent: go to X_REOF
4321 * - Fatal error read from disk: go to X_ABORT
4322 * - Error writing to net: go to X_BROKEN
4323 * - CLOSE received: goto X_DONE
4324 * 2. X_REOF After reading EOF from disk. Next:
4325 * Normally - EOF packet sent: go to X_SEOF
4326 * - Error writing EOF to net: goto X_BROKEN
4327 * - FILEPOS received: goto X_PROCESS
4328 * - CLOSE received: goto X_DONE
4329 * 3. X_SEOF After sending EOF to net.
4330 * Normally - Wait for command - stay in X_SEOF
4331 * - FILEPOS received: goto X_PROCESS
4332 * - CLOSE received: goto X_DONE
4333 * 4. X_ABORT After disk error.
4334 * Normally - Wait for command - stay in X_ABORT
4335 * - CLOSE received: goto X_DONE
4336 * 5. X_BROKEN After net error.
4337 * Normally - Wait for command - stay in X_BROKEN
4338 * - CLOSE received: goto X_DONE
4339 * 6. X_DONE Respond to close, send SYNC MARK.
4340 * Normally - Flush connection.
4341 *
4342 * WRITE (net to disk) transfers:
4343 * 1. X_PROCESS Initial state and data ransfer stats until:
4344 * Normally - DATA packets read: stay in X_PROCESS
4345 * - EOF read from net, last disk write: goto X_WSYNC
4346 * - Error reading from net:
4347 * Send ASYNCMARK on control conn, goto X_BROKEN or
4348 * or X_DONE is CLOSE already arrived.
4349 * - Error (recoverable) writing to disk:
4350 * (Remember if already got EOF)
4351 * Send ASYNCMARK on ctl, goto X_ERROR
4352 * - Error (fatal) writingto disk, goto X_WSYNC
4353 * - Read SYNCMARK, goto X_RSYNC
4354 * 2. X_WSYNC Waiting for SYNCMARK
4355 * Normally - Wait for SYNCMARK - stay in X_WSYNC
4356 * CLOSE arriving just marks conn.
4357 * - SYNCMARK arrives:
4358 * If CLOSE arrived, goto X_DONE, else goto X_RSYNC
4359 * - Error reading from net:
4360 * Send ASYNCMARK on ctl, goto X_BROKEN
4361 * - DATA or EOF read from net:
4362 * If no error so far, send ASYNCMARK - fatal,
4363 * otherwise ignore, in any case stay in X_WSYNC.
4364 * 3. X_ERROR Waiting for CONTINUE or CLOSE
4365 * Normally wait for command
4366 * - CONTINUE arrives - goto X_RETRY
4367 * - CLOSE arrives, goto X_WSYNC
4368 * 4. X_RETRY Retry disk write
4369 * - Another error - send ASYNCMARK, goto X_ERROR
4370 * - Successful, goto X_PROCESS
4371 * 5. X_RSYNC Wait for CLOSE
4372 * - Close arrives, goto X_DONE
4373 * 6. X_BROKEN Wait for CLOSE
4374 * - CLOSE arrives, goto X_DONE
4375 * 7. X_DONE Respond to CLOSE, if not BROKEN, send SYNCMARK.
4376 *
4377 */
4378 int
4379 dowork(register struct xfer *x)
4380 {
4381 /*
4382 * Now, do a unit of work on the transfer, which should be one
4383 * packet read or written to the network.
4384 * Note that this only provides task multiplexing as far as use of the
4385 * network goes, not anything else. However the non-network work
4386 * is usually just a single disk operation which is probably not worth
4387 * worrying about.
4388 */
4389 switch (x->x_options & (O_READ | O_WRITE | O_DIRECTORY | O_PROPERTIES)) {
4390 case O_READ:
4391 case O_PROPERTIES:
4392 case O_DIRECTORY:
4393 switch (x->x_state) {
4394 case X_DERROR:
4395 log(0, "X_DERROR\n");
4396 return X_FLUSH;
4397 case X_DONE:
4398 log(0, "X_DONE\n");
4399 /*
4400 * Note we must respond to the close before sending the
4401 * SYNCMARK since otherwise we would likely block on
4402 * the data connection while the other end was blocked
4403 * waiting for the CLOSE response.
4404 */
4405 xclose(x);
4406 return X_SYNCMARK;
4407 case X_BROKEN:
4408 log(0, "X_BROKEN\n"); return X_HANG;
4409 case X_ABORT:
4410 log(0, "X_ABORT\n"); return X_HANG;
4411 case X_SEOF:
4412 log(0, "X_SEOF\n"); return X_HANG;
4413 case X_IDLE:
4414 log(0, "X_IDLE\n");
4415 return X_HANG;
4416 case X_REOF:
4417 /*
4418 * We have read an EOF from the disk/directory and
4419 * flushed the last data packet into the net. So
4420 * now we send the EOF packet and wait for further
4421 * instructions (FILEPOS or CLOSE);
4422 */
4423 if (xpweof(x) < 0) {
4424 x->x_state = X_BROKEN;
4425 log(0, "xpweof(x) == %d, X_BROKEN\n", xpweof(x));
4426 } else
4427 x->x_state = X_SEOF;
4428 log(0, "X_REOF\n");
4429 return X_CONTINUE;
4430 case X_PROCESS:
4431 log(0, "X_PROCESS\n");
4432 break;
4433 default:
4434 fatal("Bad state of transfer process");
4435 }
4436 while (x->x_room != 0) {
4437 if (x->x_left == 0) {
4438 register ssize_t n;
4439
4440 if (log_verbose) {
4441 log(LOG_INFO,
4442 "Before read pos: %ld\n",
4443 tell(x->x_fd));
4444 }
4445 n = x->x_options & O_DIRECTORY ? dirread(x) :
4446 x->x_options & O_PROPERTIES ? propread(x) :
4447 read(x->x_fd, x->x_bbuf, FSBSIZE);
4448
4449 if (log_verbose) {
4450 log(LOG_INFO,
4451 "pid: %ld, x: %X, fd: %ld, "
4452 "Read: %ld\n",
4453 getpid(), x, x->x_fd, n);
4454 }
4455 switch (n) {
4456 case 0:
4457 if (xpwrite(x) < 0)
4458 x->x_state = X_BROKEN;
4459 else
4460 x->x_state = X_REOF;
4461 return X_CONTINUE;
4462 case -1:
4463 if (fherror(x->x_fh, MSC, E_FATAL, strerror(errno)) < 0)
4464 x->x_state = X_BROKEN;
4465 else
4466 x->x_state = X_ABORT;
4467 return X_CONTINUE;
4468 default:
4469 x->x_left = n;
4470 x->x_bptr = x->x_bbuf;
4471 }
4472 }
4473 switch (x->x_options & (O_CHARACTER|O_RAW|O_SUPER)) {
4474 case 0:
4475 if (x->x_bytesize <= 8) {
4476 register char *from = x->x_bptr;
4477 register char *to = x->x_pptr;
4478
4479 do {
4480 *to++ = *from++;
4481 *to++ = '\0';
4482 x->x_room -=2;
4483 } while (--x->x_left && x->x_room);
4484 x->x_bptr = from;
4485 x->x_pptr = to;
4486 break;
4487 }
4488 case O_CHARACTER | O_RAW:
4489 {
4490 /* Could use VAX movcl3 here... */
4491 register int n;
4492 register char *from = x->x_bptr;
4493 register char *to = x->x_pptr;
4494
4495 n = MIN(x->x_room, (int)x->x_left);
4496 x->x_left -= n;
4497 x->x_room -= n;
4498 do *to++ = *from++; while (--n);
4499 x->x_bptr = from;
4500 x->x_pptr = to;
4501 }
4502 break;
4503 case O_CHARACTER: /* default ascii */
4504 case O_CHARACTER | O_SUPER:
4505 to_lispm(x);
4506 break;
4507 }
4508 }
4509 if (xpwrite(x) < 0)
4510 x->x_state = X_BROKEN;
4511 else {
4512 x->x_pptr = x->x_pbuf;
4513 x->x_room = CHMAXDATA;
4514 }
4515 return X_CONTINUE;
4516 case O_WRITE:
4517 switch (x->x_state) {
4518 case X_DONE:
4519 xclose(x);
4520 return X_FLUSH;
4521 case X_BROKEN:
4522 case X_RSYNC:
4523 case X_ERROR:
4524 return X_HANG;
4525 case X_WSYNC:
4526 log(0, "X_WSYNC\n");
4527 switch (xpread(x)) {
4528 case -1:
4529 x->x_state = x->x_flags & X_CLOSE ? X_DONE : X_BROKEN;
4530 break;
4531 case -2:
4532 x->x_state = x->x_flags & X_CLOSE ? X_DONE : X_RSYNC;
4533 break;
4534 default:
4535 /*
4536 * Ignore other packets.
4537 */
4538 ;
4539 }
4540 return X_CONTINUE;
4541 case X_RETRY:
4542 if (xbwrite(x) < 0)
4543 goto writerr; /* Kludge alert */
4544 x->x_state = x->x_flags & X_EOF ? X_WSYNC : X_PROCESS;
4545 return X_CONTINUE;
4546 case X_PROCESS:
4547 {
4548 register ssize_t n;
4549
4550 log(0, "X_PROCESS\n");
4551 switch (n = xpread(x)) {
4552 case 0:
4553 log(0, "xpread 0\n");
4554 x->x_flags |= X_EOF;
4555 if (xbwrite(x) < 0)
4556 goto writerr;
4557 x->x_state = X_WSYNC;
4558 return X_CONTINUE;
4559 case -1:
4560 log(0, "xpread -1\n");
4561 (void)fherror(x->x_fh, NET, E_FATAL,
4562 "Data connection error");
4563 x->x_state = x->x_flags & X_CLOSE ? X_DONE : X_BROKEN;
4564 return X_CONTINUE;
4565 case -2:
4566 log(0, "xpread -2\n");
4567 /*
4568 * SYNCMARK before EOF, don't bother
4569 * flushing disk buffer.
4570 */
4571 x->x_state = x->x_flags & X_CLOSE ? X_DONE : X_RSYNC;
4572 return X_CONTINUE;
4573 default:
4574 log(0, "xpread default\n");
4575 x->x_left = n;
4576 x->x_pptr = x->x_pbuf;
4577 break;
4578 }
4579 }
4580 break;
4581 default:
4582 fatal("Bad transfer task state");
4583 }
4584 /*
4585 * Yow, a regular old packet full of data.
4586 */
4587 while (x->x_left) {
4588 switch (x->x_options & (O_CHARACTER|O_RAW|O_SUPER)) {
4589 case 0:
4590 if (x->x_bytesize <= 8) {
4591 register char *from = x->x_pptr;
4592 register char *to = x->x_bptr;
4593
4594 do {
4595 *to++ = *from++;
4596 from++;
4597 x->x_left -=2;
4598 } while (--x->x_room && x->x_left);
4599 x->x_pptr = from;
4600 x->x_bptr = to;
4601 break;
4602 }
4603 /* Fall into... */
4604 case O_CHARACTER | O_RAW:
4605 {
4606 register int n;
4607 register char *from = x->x_pptr;
4608 register char *to = x->x_bptr;
4609
4610 n = MIN((int)x->x_left, x->x_room);
4611 x->x_left -= n;
4612 x->x_room -= n;
4613 do *to++ = *from++; while (--n);
4614 x->x_pptr = from;
4615 x->x_bptr = to;
4616 }
4617 break;
4618 case O_CHARACTER:
4619 case O_CHARACTER | O_SUPER:
4620 from_lispm(x);
4621 break;
4622 }
4623 log(0, "x %p, x->x_room %d\n", x, x->x_room);
4624 if (x->x_room == 0) {
4625 if (xbwrite(x) >= 0) {
4626 x->x_bptr = x->x_bbuf;
4627 x->x_room = FSBSIZE;
4628 } else {
4629 writerr:
4630 if (errno == ENOSPC &&
4631 (x->x_flags & X_CLOSE) == 0) {
4632 (void)fherror(x->x_fh, NMR,
4633 E_RECOVERABLE,
4634 "File system out of space");
4635 x->x_state = X_ERROR;
4636 } else {
4637 (void)fherror(x->x_fh, MSC, E_FATAL,
4638 strerror(errno));
4639 x->x_state = X_WSYNC;
4640 }
4641 }
4642 }
4643 }
4644 log(0, "X_CONTINUE\n");
4645 return X_CONTINUE;
4646 }
4647 /* NOTREACHED */
4648 return X_BROKEN;
4649 }
4650
4651 /*
4652 * Character set conversion routines.
4653 */
4654 void
4655 to_lispm(register struct xfer *x)
4656 {
4657 register int c;
4658
4659 while (x->x_left && x->x_room) {
4660 c = *x->x_bptr++ & 0377;
4661 x->x_left--;
4662 switch (c) {
4663 case 0210: /* Map SAIL symbols back */
4664 case 0211:
4665 case 0212:
4666 case 0213:
4667 case 0214:
4668 case 0215:
4669 case 0377: /* Give back infinity */
4670 c &= 0177;
4671 break;
4672 case '\n': /* Map canonical newline to lispm */
4673 c = CHNL;
4674 break;
4675 case 015: /* Reverse linefeed map kludge */
4676 c = 0212;
4677 case 010: /* Map the format effectors back */
4678 case 011:
4679 case 013:
4680 case 014:
4681 case 0177:
4682 c |= 0200;
4683 }
4684 *x->x_pptr++ = (char)c;
4685 x->x_room--;
4686 }
4687 }
4688
4689 /*
4690 * This is the translation between the LISPM character set and
4691 * UNIX.
4692 * Several notes:
4693 * 010 through 015 and 0177 are mapped to above 0200 since UNIX needs this
4694 * range for the lispm format effectors.
4695 * The lispm format effectors 0210 through 0215 are mapped to the UNIX
4696 * ones, with the exception that 0212 maps to 015 since 0215 must map to 012.
4697 * 0177 is mapped to 0377 since its also a symbol.
4698 */
4699 void
4700 from_lispm(register struct xfer *x)
4701 {
4702 register int c;
4703
4704 while (x->x_left && x->x_room) {
4705 c = *x->x_pptr++ & 0377;
4706 switch (c) {
4707 case 010: /* Map these SAIL symbols out of the way. */
4708 case 011:
4709 case 012:
4710 case 013:
4711 case 014:
4712 case 015:
4713 case 0177:
4714 c |= 0200;
4715 break;
4716 case 0212: /* Map LINE to CR */
4717 c = 015;
4718 break;
4719 case 0215: /* Map lispm canonical newline to UNIX's */
4720 c = '\n';
4721 break;
4722 case 0210: /* Map format effectors to their right place */
4723 case 0211:
4724 case 0213:
4725 case 0214:
4726 case 0377:
4727 c &= 0177;
4728 break;
4729 }
4730 x->x_left--;
4731 *x->x_bptr++ = (char)c;
4732 x->x_room--;
4733 }
4734 }
4735
4736 /*
4737 * Write out the local disk buffer, doing the appropriate error
4738 * processing here, returning non zero if we got an error.
4739 */
4740 int
4741 xbwrite(register struct xfer *x)
4742 {
4743 register ssize_t ret;
4744 register ssize_t n;
4745
4746 if ((n = x->x_bptr - x->x_bbuf) == 0)
4747 return 0;
4748 if ((ret = write(x->x_fd, x->x_bbuf, (size_t)n)) <= 0) {
4749 log(LOG_ERR, "FILE: xbwrite error %d (%d) to file\n",
4750 ret, errno);
4751 return -1;
4752 }
4753 if (log_verbose) {
4754 log(LOG_INFO,"FILE: wrote %d bytes to file\n", ret);
4755 log(LOG_INFO,"FILE: fd %d\n", x->x_fd);
4756 }
4757 return 0;
4758 }
4759
4760 /*
4761 * Write an eof packet on a transfer.
4762 */
4763 int
4764 xpweof(register struct xfer *x)
4765 {
4766 chaos_packet *packet = chaos_allocate_packet(x->x_fh->f_connection, CHAOS_OPCODE_EOF, 0);
4767 if (chaos_connection_queue(x->x_fh->f_connection, packet))
4768 return -1;
4769 return 0;
4770 }
4771
4772 /*
4773 * Write a transfer's packet.
4774 */
4775 int
4776 xpwrite(register struct xfer *x)
4777 {
4778 register ssize_t len;
4779 chaos_connection *conn = x->x_fh->f_connection;
4780
4781 len = x->x_pptr - x->x_pbuf;
4782 if (len == 0)
4783 return 0;
4784
4785 x->x_op = x->x_options & O_BINARY ? DWDOP : DATOP;
4786 if (log_verbose) {
4787 log(LOG_INFO, "FILE: writing (%d) %d bytes to net\n",
4788 x->x_op & 0377, len);
4789 if (0) dumpbuffer((u_char *)x->x_pkt.cp_data, len);
4790 }
4791
4792 chaos_packet *packet = chaos_allocate_packet(conn, x->x_op, len);
4793 memcpy(packet->data, x->x_pkt.cp_data, len);
4794 if (chaos_connection_queue(conn, packet))
4795 return -1;
4796
4797 return 0;
4798 }
4799
4800 /*
4801 * Read a packet from the net, returning 0 for EOF packets, < 0 for errors,
4802 * and > 0 for data.
4803 */
4804 ssize_t
4805 xpread(register struct xfer *x)
4806 {
4807 register ssize_t n;
4808 chaos_packet *packet;
4809
4810 loop:
4811 packet = chaos_connection_dequeue(x->x_fh->f_connection);
4812 if (packet == 0)
4813 return -1;
4814
4815 switch ((packet->opcode & 0xff00) >> 8) {
4816 case EOFOP:
4817 {
4818 log(LOG_INFO, "xpread: EOF\n");
4819 chaos_packet *status = chaos_allocate_packet(x->x_fh->f_connection, CHAOS_OPCODE_STS, 2 * sizeof(unsigned short));
4820
4821 status->number = packet->number;
4822 *(unsigned short *)&status->data[0] = x->x_fh->f_connection->lastreceived;
4823 *(unsigned short *)&status->data[2] = x->x_fh->f_connection->rwsize;
4824
4825 chaos_connection_queue(x->x_fh->f_connection, status);
4826 free(packet);
4827 return 0;
4828 }
4829 case SYNOP:
4830 {
4831 log(LOG_INFO, "xpread: SYNOP\n");
4832 chaos_packet *status = chaos_allocate_packet(x->x_fh->f_connection, CHAOS_OPCODE_STS, 2 * sizeof(unsigned short));
4833
4834 *(unsigned short *)&status->data[0] = x->x_fh->f_connection->lastreceived;
4835 *(unsigned short *)&status->data[2] = x->x_fh->f_connection->rwsize;
4836
4837 chaos_connection_queue(x->x_fh->f_connection, status);
4838 free(packet);
4839 return -2;
4840 }
4841 case DATOP:
4842 case DWDOP:
4843 if (packet->length == 0) {
4844 log(LOG_ERR, "FILE: zero size data packet\n");
4845 goto loop; /* Zero size data packet!? */
4846 }
4847 log(LOG_INFO, "xpread: DATA length=%d\n", packet->length);
4848 n = packet->length;
4849 x->x_pkt.cp_op = (packet->opcode & 0xff00) >> 8;
4850 memcpy(x->x_pkt.cp_data, packet->data, packet->length);
4851 free(packet);
4852 return n;
4853 default:
4854 log(LOG_ERR, "FILE: bad opcode in data connection: %d\n",
4855 x->x_op & 0377);
4856 free(packet);
4857 packet = 0;
4858 fatal("Bad opcode on data connection");
4859 /* NOTREACHED */
4860 }
4861 free(packet);
4862 return -1;
4863 }
4864
4865 /*
4866 * End this program right here.
4867 * Nothing really to do since system closes everything.
4868 */
4869 void finish(int arg)
4870 {
4871 #if 0
4872 register int ufd;
4873
4874 if (getpid() == mypid && (ufd = open(FILEUTMP, 1)) >= 0) {
4875 mylogin.cl_user[0] = '\0';
4876 (void)lseek(ufd, (long)(mylogin.cl_cnum * sizeof(mylogin)), 0);
4877 (void)write(ufd, (char *)&mylogin, sizeof(mylogin));
4878 (void)close(ufd);
4879 }
4880 /* Should send close packet here */
4881 exit(0);
4882 #endif // 0
4883 }
4884 /*
4885 * Start the transfer task running.
4886 * Returns errcode if an error occurred, else 0
4887 */
4888
4889 #if defined(OSX)
4890
4891 int
4892 startxfer(struct xfer *ax)
4893 {
4894 register struct xfer *x = ax;
4895
4896 dispatch_async(dispatch_get_global_queue(0, 0), ^{
4897 log(LOG_INFO, "startxfer: entering\n");
4898
4899 for (;;) {
4900 if (log_verbose) {
4901 log(LOG_INFO, "Switch pos: %ld, status: %ld\n",
4902 tell(x->x_fd), x->x_state);
4903 }
4904
4905 while ((x->x_flags & X_CLOSE) == 0) {
4906 if (x->x_work)
4907 {
4908 struct transaction *t;
4909
4910 t = x->x_work;
4911 x->x_work = t->t_next;
4912 log(LOG_INFO, "FILE: startxfer command: %s\n", t->t_command->c_name);
4913 (*t->t_command->c_func)(x, t);
4914 }
4915 else
4916 break;
4917 }
4918
4919 switch (dowork(x)) {
4920 case X_SYNCMARK:
4921 syncmark(x->x_fh); /* Ignore errors */
4922 break;
4923 case X_FLUSH: /* Totally done */
4924 break;
4925 case X_CONTINUE: /* In process */
4926 continue;
4927 case X_HANG: /* Need more instructions */
4928 log(LOG_INFO, "Hang pos: %ld\n", tell(x->x_fd));
4929 dispatch_semaphore_wait(x->x_hangsem, DISPATCH_TIME_FOREVER);
4930 continue;
4931 }
4932 xflush(x);
4933 log(LOG_INFO, "startxfer: exiting\n");
4934 return;
4935 }
4936 });
4937 return 0;
4938 }
4939
4940 #else // !defined(OSX)
4941
4942 void *
4943 _startxfer(void *ax)
4944 {
4945 register struct xfer *x = (struct xfer *)ax;
4946
4947 log(LOG_INFO, "startxfer: entering\n");
4948 for (;;) {
4949 if (log_verbose) {
4950 log(LOG_INFO, "Switch pos: %ld, status: %ld\n",
4951 tell(x->x_fd), x->x_state);
4952 }
4953
4954 while ((x->x_flags & X_CLOSE) == 0) {
4955 if (x->x_work)
4956 {
4957 struct transaction *t;
4958
4959 t = x->x_work;
4960 x->x_work = t->t_next;
4961 log(LOG_INFO, "FILE: startxfer command: %s\n", t->t_command->c_name);
4962 (*t->t_command->c_func)(x, t);
4963 }
4964 else
4965 break;
4966 }
4967
4968 switch (dowork(x)) {
4969 case X_SYNCMARK:
4970 syncmark(x->x_fh); /* Ignore errors */
4971 break;
4972 case X_FLUSH: /* Totally done */
4973 break;
4974 case X_CONTINUE: /* In process */
4975 continue;
4976 case X_HANG: /* Need more instructions */
4977 log(LOG_INFO, "Hang pos: %ld\n", tell(x->x_fd));
4978 #if defined(OSX)
4979 dispatch_semaphore_wait(x->x_hangsem, DISPATCH_TIME_FOREVER);
4980 #else
4981 pthread_mutex_lock(&x->x_hangsem);
4982 pthread_cond_wait(&x->x_hangcond, &x->x_hangsem);
4983 pthread_mutex_unlock(&x->x_hangsem);
4984 #endif
4985 continue;
4986 }
4987 xflush(x);
4988 log(LOG_INFO, "startxfer: exiting\n");
4989 return 0;
4990 }
4991 return 0;
4992 }
4993
4994 static pthread_t startxfer_thread;
4995
4996 int
4997 startxfer(struct xfer *ax)
4998 {
4999 pthread_create(&startxfer_thread, NULL, _startxfer, (void *)ax);
5000 return 0;
5001 }
5002
5003 #endif // defined(OSX)
5004
5005 /*
5006 * Character set conversion routines.
5007 */
5008 static void
5009 buffer_to_lispm(unsigned char *data, ssize_t length)
5010 {
5011 register int c;
5012 register ssize_t i;
5013
5014 for (i = 0; i < length; i++) {
5015 c = data[i] & 0377;
5016 switch (c) {
5017 case 0210: /* Map SAIL symbols back */
5018 case 0211:
5019 case 0212:
5020 case 0213:
5021 case 0214:
5022 case 0215:
5023 case 0377: /* Give back infinity */
5024 c &= 0177;
5025 break;
5026 case '\n': /* Map canonical newline to lispm */
5027 c = CHNL;
5028 break;
5029 case 015: /* Reverse linefeed map kludge */
5030 c = 0212;
5031 case 010: /* Map the format effectors back */
5032 case 011:
5033 case 013:
5034 case 014:
5035 case 0177:
5036 c |= 0200;
5037 }
5038 data[i] = (unsigned char)c;
5039 }
5040 }
5041
5042 #if defined(OSX)
5043
5044 void
5045 processmini(chaos_connection *conn)
5046 {
5047
5048 // log(LOG_INFO, "MINI: %s\n", argv[1]);
5049 printf("processmini:\n");
5050
5051 dispatch_async(dispatch_get_global_queue(0, 0), ^{
5052
5053 int binary = 0;
5054 chaos_packet *packet;
5055 chaos_packet *output;
5056 ssize_t length;
5057 int fd;
5058 char tbuf[20];
5059 struct stat sbuf;
5060 struct tm *ptm;
5061 char *dirname;
5062 char *realname;
5063 int errcode;
5064
5065 for (;;) {
5066
5067 packet = chaos_connection_dequeue(conn);
5068 if (packet == 0)
5069 break;
5070
5071 switch (packet->opcode >> 8) {
5072 case 0200:
5073 case 0201:
5074 output = chaos_allocate_packet(conn, DWDOP, CHMAXDATA);
5075
5076 packet->data[packet->length] = '\0';
5077 printf("MINI: op %o %s\n", packet->opcode, packet->data);
5078 dirname = 0;
5079 realname = 0;
5080 if ((errcode = parsepath((char *)packet->data, &dirname, &realname, 0)) != 0)
5081 {
5082 output->opcode = 0203 << 8;
5083 printf("MINI: open failed %s\n", strerror(errno));
5084 chaos_connection_queue(conn, output);
5085 continue;
5086 }
5087 if ((fd = open(realname, O_RDONLY)) < 0) {
5088 output->opcode = 0203 << 8;
5089 printf("MINI: open failed %s\n", strerror(errno));
5090 chaos_connection_queue(conn, output);
5091 if (dirname)
5092 free(dirname);
5093 if (realname)
5094 free(realname);
5095 continue;
5096 } else {
5097 if (dirname)
5098 free(dirname);
5099 if (realname)
5100 free(realname);
5101 output->opcode = 0202 << 8;
5102 fstat(fd, &sbuf);
5103 ptm = localtime(&sbuf.st_mtime);
5104 strftime(tbuf, sizeof(tbuf), "%D %T", ptm);
5105 length = sprintf((char *)output->data, "%s%c%s", packet->data, 0215, tbuf);
5106 output->length = (unsigned short)length;
5107 chaos_connection_queue(conn, output);
5108 binary = (packet->opcode >> 8) & 1;
5109 log(LOG_INFO, "MINI: binary = %d\n", binary);
5110 }
5111 free(packet);
5112
5113 do {
5114 char buffer[CHMAXDATA];
5115
5116 length = read(fd, buffer, CHMAXDATA);
5117 /*log(LOG_INFO, "MINI: read %d\n", length);*/
5118 if (length == 0)
5119 break;
5120 output = chaos_allocate_packet(conn, (binary) ? DWDOP : DATOP, length);
5121 memcpy(output->data, buffer, length);
5122 if (binary == 0)
5123 buffer_to_lispm((unsigned char *)output->data, length);
5124 chaos_connection_queue(conn, output);
5125 } while (length > 0);
5126
5127 printf("MINI: before eof\n");
5128 output = chaos_allocate_packet(conn, EOFOP, 0);
5129 chaos_connection_queue(conn, output);
5130 close(fd);
5131 break;
5132 default:
5133 log(LOG_INFO, "MINI: op %o\n", packet->opcode >> 8);
5134 break;
5135 }
5136 }
5137 });
5138 }
5139
5140 #else // !defined(OSX)
5141
5142 void *
5143 _processmini(void *conn)
5144 {
5145 printf("processmini:\n");
5146
5147 int binary = 0;
5148 chaos_packet *packet;
5149 chaos_packet *output;
5150 ssize_t length;
5151 int fd;
5152 char tbuf[20];
5153 struct stat sbuf;
5154 struct tm *ptm;
5155 char *dirname;
5156 char *realname;
5157 int errcode;
5158
5159 for (;;) {
5160
5161 packet = chaos_connection_dequeue(conn);
5162 if (packet == 0)
5163 break;
5164
5165 switch (packet->opcode >> 8) {
5166 case 0200:
5167 case 0201:
5168 output = chaos_allocate_packet(conn, DWDOP, CHMAXDATA);
5169
5170 packet->data[packet->length] = '\0';
5171 printf("MINI: op %o %s\n", packet->opcode, packet->data);
5172 dirname = 0;
5173 realname = 0;
5174 if ((errcode = parsepath((char *)packet->data, &dirname, &realname, 0)) != 0)
5175 {
5176 output->opcode = 0203 << 8;
5177 printf("MINI: open failed %s\n", strerror(errno));
5178 chaos_connection_queue(conn, output);
5179 continue;
5180 }
5181 if ((fd = open(realname, O_RDONLY)) < 0) {
5182 output->opcode = 0203 << 8;
5183 printf("MINI: open failed %s\n", strerror(errno));
5184 chaos_connection_queue(conn, output);
5185 if (dirname)
5186 free(dirname);
5187 if (realname)
5188 free(realname);
5189 continue;
5190 } else {
5191 if (dirname)
5192 free(dirname);
5193 if (realname)
5194 free(realname);
5195 output->opcode = 0202 << 8;
5196 fstat(fd, &sbuf);
5197 ptm = localtime(&sbuf.st_mtime);
5198 strftime(tbuf, sizeof(tbuf), "%D %T", ptm);
5199 length = sprintf((char *)output->data, "%s%c%s", packet->data, 0215, tbuf);
5200 output->length = (unsigned short)length;
5201 chaos_connection_queue(conn, output);
5202 binary = (packet->opcode >> 8) & 1;
5203 log(LOG_INFO, "MINI: binary = %d\n", binary);
5204 }
5205 free(packet);
5206
5207 do {
5208 char buffer[CHMAXDATA];
5209
5210 length = read(fd, buffer, CHMAXDATA);
5211 /*log(LOG_INFO, "MINI: read %d\n", length);*/
5212 if (length == 0)
5213 break;
5214 output = chaos_allocate_packet(conn, (binary) ? DWDOP : DATOP, length);
5215 memcpy(output->data, buffer, length);
5216 if (binary == 0)
5217 buffer_to_lispm((unsigned char *)output->data, length);
5218 chaos_connection_queue(conn, output);
5219 } while (length > 0);
5220
5221 printf("MINI: before eof\n");
5222 output = chaos_allocate_packet(conn, EOFOP, 0);
5223 chaos_connection_queue(conn, output);
5224 close(fd);
5225 break;
5226 default:
5227 log(LOG_INFO, "MINI: op %o\n", packet->opcode >> 8);
5228 break;
5229 }
5230 }
5231 }
5232
5233 static pthread_t processmini_thread;
5234
5235 void
5236 processmini(chaos_connection *conn)
5237 {
5238 pthread_create(&processmini_thread, NULL, _processmini, (void *)conn);
5239 }
5240
5241 #endif // defined(OSX)

  ViewVC Help
Powered by ViewVC 1.1.5