remove empty dir
[reactos.git] / rosapps / net / ncftp / ncftp / spool.c
1 /* spool.c
2 *
3 * Copyright (c) 1992-2001 by Mike Gleason.
4 * All rights reserved.
5 *
6 */
7
8 #include "syshdrs.h"
9
10 #ifdef HAVE_LONG_FILE_NAMES
11
12 #include "spool.h"
13 #ifdef ncftp
14 # include "trace.h"
15 #endif
16 #include "util.h"
17
18 int gSpoolSerial = 0;
19 int gUnprocessedJobs = 0;
20 int gJobs = 0;
21 int gHaveSpool = -1;
22
23 extern FTPLibraryInfo gLib;
24 extern char gOurDirectoryPath[], gOurInstallationPath[];
25 extern void CloseControlConnection(const FTPCIPtr);
26
27
28
29 void
30 TruncBatchLog(void)
31 {
32 char f[256];
33 struct stat st;
34 time_t t;
35 int fd;
36
37 if (gOurDirectoryPath[0] != '\0') {
38 time(&t);
39 t -= 86400;
40 (void) OurDirectoryPath(f, sizeof(f), kSpoolLog);
41 if ((stat(f, &st) == 0) && (st.st_mtime < t)) {
42 /* Truncate old log file.
43 * Do not remove it, since a process
44 * could still conceivably be going.
45 */
46 fd = open(f, O_WRONLY|O_TRUNC, 00600);
47 if (fd >= 0)
48 close(fd);
49 }
50 }
51 } /* TruncBatchLog */
52
53
54
55 int
56 MkSpoolDir(char *sdir, size_t size)
57 {
58 struct stat st;
59 *sdir = '\0';
60
61 /* Don't create in root directory. */
62 if (gOurDirectoryPath[0] != '\0') {
63 (void) OurDirectoryPath(sdir, size, kSpoolDir);
64 if ((stat(sdir, &st) < 0) && (MkDirs(sdir, 00700) < 0)) {
65 perror(sdir);
66 return (-1);
67 } else {
68 return (0);
69 }
70 }
71 return (-1);
72 } /* MkSpoolDir */
73
74
75
76
77 void
78 SpoolName(const char *const sdir, char *sp, size_t size, int flag, int serial, time_t when)
79 {
80 char sname[64];
81 char dstr[32];
82 struct tm *ltp;
83
84 if ((when == (time_t) 0) || (when == (time_t) -1))
85 (void) time(&when);
86 ltp = localtime(&when);
87 if (ltp == NULL) {
88 /* impossible */
89 (void) Strncpy(dstr, "19700101-000000", size);
90 } else {
91 (void) strftime(dstr, sizeof(dstr), "%Y%m%d-%H%M%S", ltp);
92 }
93 (void) Strncpy(sp, sdir, size);
94 (void) sprintf(sname, "/%c-%010u-%04x-%s",
95 flag,
96 (unsigned int) getpid(),
97 (serial % (16 * 16 * 16 * 16)),
98 dstr
99 );
100 (void) Strncat(sp, sname, size);
101 } /* SpoolName */
102
103
104
105
106 int
107 HaveSpool(void)
108 {
109 #if defined(WIN32) || defined(_WINDOWS)
110 char ncftpbatch[260];
111
112 if (gHaveSpool < 0) {
113 gHaveSpool = 0;
114 if (gOurInstallationPath[0] != '\0') {
115 OurInstallationPath(ncftpbatch, sizeof(ncftpbatch), "ncftpbatch.exe");
116 gHaveSpool = (access(ncftpbatch, F_OK) == 0) ? 1 : 0;
117 }
118 }
119 #elif defined(BINDIR)
120 char ncftpbatch[256];
121
122 if (gHaveSpool < 0) {
123 STRNCPY(ncftpbatch, BINDIR);
124 STRNCAT(ncftpbatch, "/");
125 STRNCAT(ncftpbatch, "ncftpbatch");
126 gHaveSpool = (access(ncftpbatch, X_OK) == 0) ? 1 : 0;
127 }
128 #else /* BINDIR */
129 if (gHaveSpool < 0) {
130 if (geteuid() == 0) {
131 gHaveSpool = (access("/usr/bin/ncftpbatch", X_OK) == 0) ? 1 : 0;
132 } else {
133 gHaveSpool = (system("ncftpbatch -X") == 0) ? 1 : 0;
134 }
135 }
136 #endif /* BINDIR */
137
138 return (gHaveSpool);
139 } /* HaveSpool */
140
141
142
143
144 int
145 CanSpool(void)
146 {
147 char sdir[256];
148
149 if (gOurDirectoryPath[0] == '\0') {
150 return (-1);
151 }
152 if (MkSpoolDir(sdir, sizeof(sdir)) < 0)
153 return (-1);
154 return (0);
155 } /* CanSpool */
156
157
158
159
160 int
161 SpoolX(
162 const char *const op,
163 const char *const rfile,
164 const char *const rdir,
165 const char *const lfile,
166 const char *const ldir,
167 const char *const host,
168 const char *const ip,
169 const unsigned int port,
170 const char *const user,
171 const char *const passclear,
172 int xtype,
173 int recursive,
174 int delete,
175 int passive,
176 const char *const precmd,
177 const char *const perfilecmd,
178 const char *const postcmd,
179 time_t when)
180 {
181 char sdir[256];
182 char pass[160];
183 char spathname[256];
184 char spathname2[256];
185 char ldir2[256];
186 FILE *fp;
187 #if defined(WIN32) || defined(_WINDOWS)
188 #else
189 mode_t um;
190 #endif
191
192 if (MkSpoolDir(sdir, sizeof(sdir)) < 0)
193 return (-1);
194
195 gSpoolSerial++;
196 SpoolName(sdir, spathname2, sizeof(spathname2), op[0], gSpoolSerial, when);
197 SpoolName(sdir, spathname, sizeof(spathname), 'z', gSpoolSerial, when);
198 #if defined(WIN32) || defined(_WINDOWS)
199 fp = fopen(spathname, FOPEN_WRITE_TEXT);
200 #else
201 um = umask(077);
202 fp = fopen(spathname, FOPEN_WRITE_TEXT);
203 (void) umask(um);
204 #endif
205 if (fp == NULL)
206 return (-1);
207
208 if (fprintf(fp, "# This is a NcFTP spool file entry.\n# Run the \"ncftpbatch\" program to process the spool directory.\n#\n") < 0)
209 goto err;
210 if (fprintf(fp, "op=%s\n", op) < 0)
211 goto err;
212 if (fprintf(fp, "hostname=%s\n", host) < 0)
213 goto err;
214 if ((ip != NULL) && (ip[0] != '\0') && (fprintf(fp, "host-ip=%s\n", ip) < 0))
215 goto err;
216 if ((port > 0) && (port != (unsigned int) kDefaultFTPPort) && (fprintf(fp, "port=%u\n", port) < 0))
217 goto err;
218 if ((user != NULL) && (user[0] != '\0') && (strcmp(user, "anonymous") != 0) && (fprintf(fp, "user=%s\n", user) < 0))
219 goto err;
220 if ((strcmp(user, "anonymous") != 0) && (passclear != NULL) && (passclear[0] != '\0')) {
221 (void) memcpy(pass, kPasswordMagic, kPasswordMagicLen);
222 ToBase64(pass + kPasswordMagicLen, passclear, strlen(passclear), 1);
223 if (fprintf(fp, "pass=%s\n", pass) < 0)
224 goto err;
225 } else if ((strcmp(user, "anonymous") == 0) && (gLib.defaultAnonPassword[0] != '\0')) {
226 if (fprintf(fp, "anon-pass=%s\n", gLib.defaultAnonPassword) < 0)
227 goto err;
228 }
229 if (fprintf(fp, "xtype=%c\n", xtype) < 0)
230 goto err;
231 if ((recursive != 0) && (fprintf(fp, "recursive=%s\n", YESNO(recursive)) < 0))
232 goto err;
233 if ((delete != 0) && (fprintf(fp, "delete=%s\n", YESNO(delete)) < 0))
234 goto err;
235 if (fprintf(fp, "passive=%d\n", passive) < 0)
236 goto err;
237 if (fprintf(fp, "remote-dir=%s\n", rdir) < 0)
238 goto err;
239 if ((ldir == NULL) || (ldir[0] == '\0') || (strcmp(ldir, ".") == 0)) {
240 /* Use current process' working directory. */
241 FTPGetLocalCWD(ldir2, sizeof(ldir2));
242 if (fprintf(fp, "local-dir=%s\n", ldir2) < 0)
243 goto err;
244 } else {
245 if (fprintf(fp, "local-dir=%s\n", ldir) < 0)
246 goto err;
247 }
248 if (fprintf(fp, "remote-file=%s\n", rfile) < 0)
249 goto err;
250 if (fprintf(fp, "local-file=%s\n", lfile) < 0)
251 goto err;
252 if ((precmd != NULL) && (precmd[0] != '\0') && (fprintf(fp, "pre-command=%s\n", precmd) < 0))
253 goto err;
254 if ((perfilecmd != NULL) && (perfilecmd[0] != '\0') && (fprintf(fp, "per-file-command=%s\n", perfilecmd) < 0))
255 goto err;
256 if ((postcmd != NULL) && (postcmd[0] != '\0') && (fprintf(fp, "post-command=%s\n", postcmd) < 0))
257 goto err;
258
259 if (fclose(fp) < 0)
260 goto err2;
261
262 /* Move the spool file into its "live" name. */
263 if (rename(spathname, spathname2) < 0) {
264 perror("rename spoolfile failed");
265 goto err3;
266 }
267 gUnprocessedJobs++;
268 return (0);
269
270 err:
271 (void) fclose(fp);
272 err2:
273 perror("write to spool file failed");
274 err3:
275 (void) unlink(spathname);
276 return (-1);
277 }
278
279
280
281 #if defined(WIN32) || defined(_WINDOWS)
282 #else
283 static int
284 PWrite(int sfd, const char *const buf0, size_t size)
285 {
286 int nleft;
287 const char *buf = buf0;
288 int nwrote;
289
290 nleft = (int) size;
291 for (;;) {
292 nwrote = (int) write(sfd, buf, nleft);
293 if (nwrote < 0) {
294 if (errno != EINTR) {
295 nwrote = (int) size - nleft;
296 if (nwrote == 0)
297 nwrote = -1;
298 return (nwrote);
299 } else {
300 errno = 0;
301 nwrote = 0;
302 /* Try again. */
303 }
304 }
305 nleft -= nwrote;
306 if (nleft <= 0)
307 break;
308 buf += nwrote;
309 }
310 nwrote = (int) size - nleft;
311 return (nwrote);
312 } /* PWrite */
313 #endif
314
315
316
317 void
318 Jobs(void)
319 {
320 #if defined(WIN32) || defined(_WINDOWS)
321 assert(0); // Not supported
322 #else
323 char *argv[8];
324 pid_t pid;
325 #ifdef BINDIR
326 char ncftpbatch[256];
327
328 STRNCPY(ncftpbatch, BINDIR);
329 STRNCAT(ncftpbatch, "/");
330 STRNCAT(ncftpbatch, "ncftpbatch");
331 #endif /* BINDIR */
332
333 pid = fork();
334 if (pid < 0) {
335 perror("fork");
336 } else if (pid == 0) {
337 argv[0] = (char *) "ncftpbatch";
338 argv[1] = (char *) "-l";
339 argv[2] = NULL;
340
341 #ifdef BINDIR
342 (void) execv(ncftpbatch, argv);
343 (void) fprintf(stderr, "Could not run %s. Is it in installed as %s?\n", argv[0], ncftpbatch);
344 #else /* BINDIR */
345 (void) execvp(argv[0], argv);
346 (void) fprintf(stderr, "Could not run %s. Is it in your $PATH?\n", argv[0]);
347 #endif /* BINDIR */
348 perror(argv[0]);
349 exit(1);
350 } else {
351 #ifdef HAVE_WAITPID
352 (void) waitpid(pid, NULL, 0);
353 #else
354 (void) wait(NULL);
355 #endif
356 }
357 #endif
358 } /* Jobs */
359
360
361
362
363 void
364 RunBatch(int Xstruct, const FTPCIPtr cip)
365 {
366 #if defined(WIN32) || defined(_WINDOWS)
367 char ncftpbatch[260];
368 const char *prog;
369 int winExecResult;
370
371 if (gOurInstallationPath[0] == '\0') {
372 (void) fprintf(stderr, "Cannot find path to %s. Please re-run Setup.\n", "ncftpbatch.exe");
373 return;
374 }
375 prog = ncftpbatch;
376 OurInstallationPath(ncftpbatch, sizeof(ncftpbatch), "ncftpbatch.exe");
377
378 winExecResult = WinExec(prog, SW_SHOWNORMAL);
379 if (winExecResult <= 31) switch (winExecResult) {
380 case ERROR_BAD_FORMAT:
381 fprintf(stderr, "Could not run %s: %s\n", prog, "The .EXE file is invalid");
382 return;
383 case ERROR_FILE_NOT_FOUND:
384 fprintf(stderr, "Could not run %s: %s\n", prog, "The specified file was not found.");
385 return;
386 case ERROR_PATH_NOT_FOUND:
387 fprintf(stderr, "Could not run %s: %s\n", prog, "The specified path was not found.");
388 return;
389 default:
390 fprintf(stderr, "Could not run %s: Unknown error #%d.\n", prog, winExecResult);
391 return;
392 }
393 #else
394 int pfd[2];
395 char pfdstr[32];
396 char *argv[8];
397 pid_t pid = 0;
398 #ifdef BINDIR
399 char ncftpbatch[256];
400
401 STRNCPY(ncftpbatch, BINDIR);
402 STRNCAT(ncftpbatch, "/");
403 STRNCAT(ncftpbatch, "ncftpbatch");
404 #endif /* BINDIR */
405
406 if (Xstruct != 0) {
407 if (pipe(pfd) < 0) {
408 perror("pipe");
409 }
410
411 (void) sprintf(pfdstr, "%d", pfd[0]);
412 pid = fork();
413 if (pid < 0) {
414 (void) close(pfd[0]);
415 (void) close(pfd[1]);
416 perror("fork");
417 } else if (pid == 0) {
418 (void) close(pfd[1]); /* Child closes write end. */
419 argv[0] = (char *) "ncftpbatch";
420 #ifdef DEBUG_NCFTPBATCH
421 argv[1] = (char *) "-SD";
422 #else
423 argv[1] = (char *) "-d";
424 #endif
425 argv[2] = (char *) "-|";
426 argv[3] = pfdstr;
427 argv[4] = NULL;
428
429 #ifdef BINDIR
430 (void) execv(ncftpbatch, argv);
431 (void) fprintf(stderr, "Could not run %s. Is it in installed as %s?\n", argv[0], ncftpbatch);
432 #else /* BINDIR */
433 (void) execvp(argv[0], argv);
434 (void) fprintf(stderr, "Could not run %s. Is it in your $PATH?\n", argv[0]);
435 #endif /* BINDIR */
436 perror(argv[0]);
437 exit(1);
438 }
439 (void) close(pfd[0]); /* Parent closes read end. */
440 (void) PWrite(pfd[1], (const char *) cip->lip, sizeof(FTPLibraryInfo));
441 (void) PWrite(pfd[1], (const char *) cip, sizeof(FTPConnectionInfo));
442 (void) close(pfd[1]); /* Parent closes read end. */
443
444 /* Close it now, or else this process would send
445 * the server a QUIT message. This will cause it
446 * to think it already has.
447 */
448 CloseControlConnection(cip);
449 } else {
450 pid = fork();
451 if (pid < 0) {
452 perror("fork");
453 } else if (pid == 0) {
454 argv[0] = (char *) "ncftpbatch";
455 argv[1] = (char *) "-d";
456 argv[2] = NULL;
457 #ifdef BINDIR
458 (void) execv(ncftpbatch, argv);
459 (void) fprintf(stderr, "Could not run %s. Is it in installed as %s?\n", argv[0], ncftpbatch);
460 #else /* BINDIR */
461 (void) execvp(argv[0], argv);
462 (void) fprintf(stderr, "Could not run %s. Is it in your $PATH?\n", argv[0]);
463 #endif /* BINDIR */
464 perror(argv[0]);
465 exit(1);
466 }
467 }
468
469 if (pid > 1) {
470 #ifdef HAVE_WAITPID
471 (void) waitpid(pid, NULL, 0);
472 #else
473 (void) wait(NULL);
474 #endif
475 }
476 #endif
477 } /* RunBatch */
478
479
480
481 void
482 RunBatchIfNeeded(const FTPCIPtr cip)
483 {
484 if (gUnprocessedJobs > 0) {
485 #ifdef ncftp
486 Trace(0, "Running ncftp_batch for %d job%s.\n", gUnprocessedJobs, gUnprocessedJobs > 0 ? "s" : "");
487 gUnprocessedJobs = 0;
488 RunBatch(1, cip);
489 #else
490 gUnprocessedJobs = 0;
491 RunBatch(0, cip);
492 #endif
493 }
494 } /* RunBatchIfNeeded */
495
496 #endif /* HAVE_LONG_FILE_NAMES */