source: trunk/server/source3/client/clitar.c@ 751

Last change on this file since 751 was 751, checked in by Silvan Scherrer, 13 years ago

Samba Server: updated trunk to 3.6.9

File size: 52.8 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3 Tar Extensions
4 Copyright (C) Ricky Poulten 1995-1998
5 Copyright (C) Richard Sharpe 1998
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
19*/
20/* The following changes developed by Richard Sharpe for Canon Information
21 Systems Research Australia (CISRA)
22
23 1. Restore can now restore files with long file names
24 2. Save now saves directory information so that we can restore
25 directory creation times
26 3. tar now accepts both UNIX path names and DOS path names. I prefer
27 those lovely /'s to those UGLY \'s :-)
28 4. the files to exclude can be specified as a regular expression by adding
29 an r flag to the other tar flags. Eg:
30
31 -TcrX file.tar "*.(obj|exe)"
32
33 will skip all .obj and .exe files
34*/
35
36
37#include "includes.h"
38#include "system/filesys.h"
39#include "clitar.h"
40#include "client/client_proto.h"
41#include "libsmb/libsmb.h"
42
43static int clipfind(char **aret, int ret, char *tok);
44
45typedef struct file_info_struct file_info2;
46
47struct file_info_struct {
48 SMB_OFF_T size;
49 uint16 mode;
50 uid_t uid;
51 gid_t gid;
52 /* These times are normally kept in GMT */
53 struct timespec mtime_ts;
54 struct timespec atime_ts;
55 struct timespec ctime_ts;
56 char *name; /* This is dynamically allocated */
57 file_info2 *next, *prev; /* Used in the stack ... */
58};
59
60typedef struct {
61 file_info2 *top;
62 int items;
63} stack;
64
65#define SEPARATORS " \t\n\r"
66extern time_t newer_than;
67extern struct cli_state *cli;
68
69/* These defines are for the do_setrattr routine, to indicate
70 * setting and reseting of file attributes in the function call */
71#define ATTRSET 1
72#define ATTRRESET 0
73
74static uint16 attribute = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
75
76#ifndef CLIENT_TIMEOUT
77#define CLIENT_TIMEOUT (30*1000)
78#endif
79
80static char *tarbuf, *buffer_p;
81static int tp, ntarf, tbufsiz;
82static double ttarf;
83/* Incremental mode */
84static bool tar_inc=False;
85/* Reset archive bit */
86static bool tar_reset=False;
87/* Include / exclude mode (true=include, false=exclude) */
88static bool tar_excl=True;
89/* use regular expressions for search on file names */
90static bool tar_re_search=False;
91/* Do not dump anything, just calculate sizes */
92static bool dry_run=False;
93/* Dump files with System attribute */
94static bool tar_system=True;
95/* Dump files with Hidden attribute */
96static bool tar_hidden=True;
97/* Be noisy - make a catalogue */
98static bool tar_noisy=True;
99static bool tar_real_noisy=False; /* Don't want to be really noisy by default */
100
101char tar_type='\0';
102static char **cliplist=NULL;
103static int clipn=0;
104static bool must_free_cliplist = False;
105extern const char *cmd_ptr;
106
107extern bool lowercase;
108extern uint16 cnum;
109extern bool readbraw_supported;
110extern int max_xmit;
111extern int get_total_time_ms;
112extern int get_total_size;
113
114static int blocksize=20;
115static int tarhandle;
116
117static void writetarheader(int f, const char *aname, uint64_t size, time_t mtime,
118 const char *amode, unsigned char ftype);
119static NTSTATUS do_atar(const char *rname_in, char *lname,
120 struct file_info *finfo1);
121static NTSTATUS do_tar(struct cli_state *cli_state, struct file_info *finfo,
122 const char *dir);
123static void oct_it(uint64_t value, int ndgs, char *p);
124static void fixtarname(char *tptr, const char *fp, size_t l);
125static int dotarbuf(int f, char *b, int n);
126static void dozerobuf(int f, int n);
127static void dotareof(int f);
128static void initarbuf(void);
129
130/* restore functions */
131static long readtarheader(union hblock *hb, file_info2 *finfo, const char *prefix);
132static long unoct(char *p, int ndgs);
133static void do_tarput(void);
134static void unfixtarname(char *tptr, char *fp, int l, bool first);
135
136/*
137 * tar specific utitlities
138 */
139
140/*******************************************************************
141Create a string of size size+1 (for the null)
142*******************************************************************/
143
144static char *string_create_s(int size)
145{
146 char *tmp;
147
148 tmp = (char *)SMB_MALLOC(size+1);
149
150 if (tmp == NULL) {
151 DEBUG(0, ("Out of memory in string_create_s\n"));
152 }
153
154 return(tmp);
155}
156
157/****************************************************************************
158Write a tar header to buffer
159****************************************************************************/
160
161static void writetarheader(int f, const char *aname, uint64_t size, time_t mtime,
162 const char *amode, unsigned char ftype)
163{
164 union hblock hb;
165 int i, chk, l;
166 char *jp;
167
168 DEBUG(5, ("WriteTarHdr, Type = %c, Size= %.0f, Name = %s\n", ftype, (double)size, aname));
169
170 memset(hb.dummy, 0, sizeof(hb.dummy));
171
172 l=strlen(aname);
173 /* We will be prepending a '.' in fixtarheader so use +2 to
174 * take care of the . and terminating zero. JRA.
175 */
176 if (l+2 >= NAMSIZ) {
177 /* write a GNU tar style long header */
178 char *b;
179 b = (char *)SMB_MALLOC(l+TBLOCK+100);
180 if (!b) {
181 DEBUG(0,("out of memory\n"));
182 exit(1);
183 }
184 writetarheader(f, "/./@LongLink", l+2, 0, " 0 \0", 'L');
185 memset(b, 0, l+TBLOCK+100);
186 fixtarname(b, aname, l+2);
187 i = strlen(b)+1;
188 DEBUG(5, ("File name in tar file: %s, size=%d, \n", b, (int)strlen(b)));
189 dotarbuf(f, b, TBLOCK*(((i-1)/TBLOCK)+1));
190 SAFE_FREE(b);
191 }
192
193 fixtarname(hb.dbuf.name, aname, (l+2 >= NAMSIZ) ? NAMSIZ : l + 2);
194
195 if (lowercase)
196 strlower_m(hb.dbuf.name);
197
198 /* write out a "standard" tar format header */
199
200 hb.dbuf.name[NAMSIZ-1]='\0';
201 safe_strcpy(hb.dbuf.mode, amode, sizeof(hb.dbuf.mode)-1);
202 oct_it((uint64_t)0, 8, hb.dbuf.uid);
203 oct_it((uint64_t)0, 8, hb.dbuf.gid);
204 oct_it((uint64_t) size, 13, hb.dbuf.size);
205 if (size > (uint64_t)077777777777LL) {
206 /* This is a non-POSIX compatible extention to store files
207 greater than 8GB. */
208
209 memset(hb.dbuf.size, 0, 4);
210 hb.dbuf.size[0]=128;
211 for (i = 8; i; i--) {
212 hb.dbuf.size[i+3] = size & 0xff;
213 size >>= 8;
214 }
215 }
216 oct_it((uint64_t) mtime, 13, hb.dbuf.mtime);
217 memcpy(hb.dbuf.chksum, " ", sizeof(hb.dbuf.chksum));
218 memset(hb.dbuf.linkname, 0, NAMSIZ);
219 hb.dbuf.linkflag=ftype;
220
221 for (chk=0, i=sizeof(hb.dummy), jp=hb.dummy; --i>=0;)
222 chk+=(0xFF & *jp++);
223
224 oct_it((uint64_t) chk, 8, hb.dbuf.chksum);
225 hb.dbuf.chksum[6] = '\0';
226
227 (void) dotarbuf(f, hb.dummy, sizeof(hb.dummy));
228}
229
230/****************************************************************************
231Read a tar header into a hblock structure, and validate
232***************************************************************************/
233
234static long readtarheader(union hblock *hb, file_info2 *finfo, const char *prefix)
235{
236 long chk, fchk;
237 int i;
238 char *jp;
239
240 /*
241 * read in a "standard" tar format header - we're not that interested
242 * in that many fields, though
243 */
244
245 /* check the checksum */
246 for (chk=0, i=sizeof(hb->dummy), jp=hb->dummy; --i>=0;)
247 chk+=(0xFF & *jp++);
248
249 if (chk == 0)
250 return chk;
251
252 /* compensate for blanks in chksum header */
253 for (i=sizeof(hb->dbuf.chksum), jp=hb->dbuf.chksum; --i>=0;)
254 chk-=(0xFF & *jp++);
255
256 chk += ' ' * sizeof(hb->dbuf.chksum);
257
258 fchk=unoct(hb->dbuf.chksum, sizeof(hb->dbuf.chksum));
259
260 DEBUG(5, ("checksum totals chk=%ld fchk=%ld chksum=%s\n",
261 chk, fchk, hb->dbuf.chksum));
262
263 if (fchk != chk) {
264 DEBUG(0, ("checksums don't match %ld %ld\n", fchk, chk));
265 dump_data(5, (uint8 *)hb - TBLOCK, TBLOCK *3);
266 return -1;
267 }
268
269 if ((finfo->name = string_create_s(strlen(prefix) + strlen(hb -> dbuf.name) + 3)) == NULL) {
270 DEBUG(0, ("Out of space creating file_info2 for %s\n", hb -> dbuf.name));
271 return(-1);
272 }
273
274 safe_strcpy(finfo->name, prefix, strlen(prefix) + strlen(hb -> dbuf.name) + 3);
275
276 /* use l + 1 to do the null too; do prefix - prefcnt to zap leading slash */
277 unfixtarname(finfo->name + strlen(prefix), hb->dbuf.name,
278 strlen(hb->dbuf.name) + 1, True);
279
280 /* can't handle some links at present */
281 if ((hb->dbuf.linkflag != '0') && (hb -> dbuf.linkflag != '5')) {
282 if (hb->dbuf.linkflag == 0) {
283 DEBUG(6, ("Warning: NULL link flag (gnu tar archive ?) %s\n",
284 finfo->name));
285 } else {
286 if (hb -> dbuf.linkflag == 'L') { /* We have a longlink */
287 /* Do nothing here at the moment. do_tarput will handle this
288 as long as the longlink gets back to it, as it has to advance
289 the buffer pointer, etc */
290 } else {
291 DEBUG(0, ("this tar file appears to contain some kind \
292of link other than a GNUtar Longlink - ignoring\n"));
293 return -2;
294 }
295 }
296 }
297
298 if ((unoct(hb->dbuf.mode, sizeof(hb->dbuf.mode)) & S_IFDIR) ||
299 (*(finfo->name+strlen(finfo->name)-1) == '\\')) {
300 finfo->mode=FILE_ATTRIBUTE_DIRECTORY;
301 } else {
302 finfo->mode=0; /* we don't care about mode at the moment, we'll
303 * just make it a regular file */
304 }
305
306 /*
307 * Bug fix by richard@sj.co.uk
308 *
309 * REC: restore times correctly (as does tar)
310 * We only get the modification time of the file; set the creation time
311 * from the mod. time, and the access time to current time
312 */
313 finfo->mtime_ts = finfo->ctime_ts =
314 convert_time_t_to_timespec((time_t)strtol(hb->dbuf.mtime, NULL, 8));
315 finfo->atime_ts = convert_time_t_to_timespec(time(NULL));
316 if ((hb->dbuf.size[0] & 0xff) == 0x80) {
317 /* This is a non-POSIX compatible extention to extract files
318 greater than 8GB. */
319 finfo->size = 0;
320 for (i = 0; i < 8; i++) {
321 finfo->size <<= 8;
322 finfo->size |= hb->dbuf.size[i+4] & 0xff;
323 }
324 } else {
325 finfo->size = unoct(hb->dbuf.size, sizeof(hb->dbuf.size));
326 }
327
328 return True;
329}
330
331/****************************************************************************
332Write out the tar buffer to tape or wherever
333****************************************************************************/
334
335static int dotarbuf(int f, char *b, int n)
336{
337 int fail=1, writ=n;
338
339 if (dry_run) {
340 return writ;
341 }
342 /* This routine and the next one should be the only ones that do write()s */
343 if (tp + n >= tbufsiz) {
344 int diff;
345
346 diff=tbufsiz-tp;
347 memcpy(tarbuf + tp, b, diff);
348 fail=fail && (1+sys_write(f, tarbuf, tbufsiz));
349 n-=diff;
350 b+=diff;
351 tp=0;
352
353 while (n >= tbufsiz) {
354 fail=fail && (1 + sys_write(f, b, tbufsiz));
355 n-=tbufsiz;
356 b+=tbufsiz;
357 }
358 }
359
360 if (n>0) {
361 memcpy(tarbuf+tp, b, n);
362 tp+=n;
363 }
364
365 return(fail ? writ : 0);
366}
367
368/****************************************************************************
369Write zeros to buffer / tape
370****************************************************************************/
371
372static void dozerobuf(int f, int n)
373{
374 /* short routine just to write out n zeros to buffer -
375 * used to round files to nearest block
376 * and to do tar EOFs */
377
378 if (dry_run)
379 return;
380
381 if (n+tp >= tbufsiz) {
382 memset(tarbuf+tp, 0, tbufsiz-tp);
383 if (sys_write(f, tarbuf, tbufsiz) != tbufsiz) {
384 DEBUG(0, ("dozerobuf: sys_write fail\n"));
385 return;
386 }
387 memset(tarbuf, 0, (tp+=n-tbufsiz));
388 } else {
389 memset(tarbuf+tp, 0, n);
390 tp+=n;
391 }
392}
393
394/****************************************************************************
395Malloc tape buffer
396****************************************************************************/
397
398static void initarbuf(void)
399{
400 /* initialize tar buffer */
401 tbufsiz=blocksize*TBLOCK;
402 tarbuf=(char *)SMB_MALLOC(tbufsiz); /* FIXME: We might not get the buffer */
403
404 /* reset tar buffer pointer and tar file counter and total dumped */
405 tp=0; ntarf=0; ttarf=0;
406}
407
408/****************************************************************************
409Write two zero blocks at end of file
410****************************************************************************/
411
412static void dotareof(int f)
413{
414 SMB_STRUCT_STAT stbuf;
415 /* Two zero blocks at end of file, write out full buffer */
416
417 if (dry_run)
418 return;
419
420 (void) dozerobuf(f, TBLOCK);
421 (void) dozerobuf(f, TBLOCK);
422
423 if (sys_fstat(f, &stbuf, false) == -1) {
424 DEBUG(0, ("Couldn't stat file handle\n"));
425 return;
426 }
427
428 /* Could be a pipe, in which case S_ISREG should fail,
429 * and we should write out at full size */
430 if (tp > 0) {
431 size_t towrite = S_ISREG(stbuf.st_ex_mode) ? tp : tbufsiz;
432 if (sys_write(f, tarbuf, towrite) != towrite) {
433 DEBUG(0,("dotareof: sys_write fail\n"));
434 }
435 }
436}
437
438/****************************************************************************
439(Un)mangle DOS pathname, make nonabsolute
440****************************************************************************/
441
442static void fixtarname(char *tptr, const char *fp, size_t l)
443{
444 /* add a '.' to start of file name, convert from ugly dos \'s in path
445 * to lovely unix /'s :-} */
446 *tptr++='.';
447 l--;
448
449 StrnCpy(tptr, fp, l-1);
450 string_replace(tptr, '\\', '/');
451}
452
453/****************************************************************************
454Convert from decimal to octal string
455****************************************************************************/
456
457static void oct_it (uint64_t value, int ndgs, char *p)
458{
459 /* Converts long to octal string, pads with leading zeros */
460
461 /* skip final null, but do final space */
462 --ndgs;
463 p[--ndgs] = ' ';
464
465 /* Loop does at least one digit */
466 do {
467 p[--ndgs] = '0' + (char) (value & 7);
468 value >>= 3;
469 } while (ndgs > 0 && value != 0);
470
471 /* Do leading zeros */
472 while (ndgs > 0)
473 p[--ndgs] = '0';
474}
475
476/****************************************************************************
477Convert from octal string to long
478***************************************************************************/
479
480static long unoct(char *p, int ndgs)
481{
482 long value=0;
483 /* Converts octal string to long, ignoring any non-digit */
484
485 while (--ndgs) {
486 if (isdigit((int)*p))
487 value = (value << 3) | (long) (*p - '0');
488
489 p++;
490 }
491
492 return value;
493}
494
495/****************************************************************************
496Compare two strings in a slash insensitive way, allowing s1 to match s2
497if s1 is an "initial" string (up to directory marker). Thus, if s2 is
498a file in any subdirectory of s1, declare a match.
499***************************************************************************/
500
501static int strslashcmp(char *s1, char *s2)
502{
503 char *s1_0=s1;
504
505 while(*s1 && *s2 && (*s1 == *s2 || tolower_m(*s1) == tolower_m(*s2) ||
506 (*s1 == '\\' && *s2=='/') || (*s1 == '/' && *s2=='\\'))) {
507 s1++; s2++;
508 }
509
510 /* if s1 has a trailing slash, it compared equal, so s1 is an "initial"
511 string of s2.
512 */
513 if (!*s1 && s1 != s1_0 && (*(s1-1) == '/' || *(s1-1) == '\\'))
514 return 0;
515
516 /* ignore trailing slash on s1 */
517 if (!*s2 && (*s1 == '/' || *s1 == '\\') && !*(s1+1))
518 return 0;
519
520 /* check for s1 is an "initial" string of s2 */
521 if ((*s2 == '/' || *s2 == '\\') && !*s1)
522 return 0;
523
524 return *s1-*s2;
525}
526
527/****************************************************************************
528Ensure a remote path exists (make if necessary)
529***************************************************************************/
530
531static bool ensurepath(const char *fname)
532{
533 /* *must* be called with buffer ready malloc'ed */
534 /* ensures path exists */
535
536 char *partpath, *ffname;
537 const char *p=fname;
538 char *basehack;
539 char *saveptr;
540
541 DEBUG(5, ( "Ensurepath called with: %s\n", fname));
542
543 partpath = string_create_s(strlen(fname));
544 ffname = string_create_s(strlen(fname));
545
546 if ((partpath == NULL) || (ffname == NULL)){
547 DEBUG(0, ("Out of memory in ensurepath: %s\n", fname));
548 SAFE_FREE(partpath);
549 SAFE_FREE(ffname);
550 return(False);
551 }
552
553 *partpath = 0;
554
555 /* fname copied to ffname so can strtok_r */
556
557 safe_strcpy(ffname, fname, strlen(fname));
558
559 /* do a `basename' on ffname, so don't try and make file name directory */
560 if ((basehack=strrchr_m(ffname, '\\')) == NULL) {
561 SAFE_FREE(partpath);
562 SAFE_FREE(ffname);
563 return True;
564 } else {
565 *basehack='\0';
566 }
567
568 p=strtok_r(ffname, "\\", &saveptr);
569
570 while (p) {
571 safe_strcat(partpath, p, strlen(fname) + 1);
572
573 if (!NT_STATUS_IS_OK(cli_chkpath(cli, partpath))) {
574 if (!NT_STATUS_IS_OK(cli_mkdir(cli, partpath))) {
575 SAFE_FREE(partpath);
576 SAFE_FREE(ffname);
577 DEBUG(0, ("Error mkdir %s\n", cli_errstr(cli)));
578 return False;
579 } else {
580 DEBUG(3, ("mkdirhiering %s\n", partpath));
581 }
582 }
583
584 safe_strcat(partpath, "\\", strlen(fname) + 1);
585 p = strtok_r(NULL, "/\\", &saveptr);
586 }
587
588 SAFE_FREE(partpath);
589 SAFE_FREE(ffname);
590 return True;
591}
592
593static int padit(char *buf, uint64_t bufsize, uint64_t padsize)
594{
595 int berr= 0;
596 int bytestowrite;
597
598 DEBUG(5, ("Padding with %0.f zeros\n", (double)padsize));
599 memset(buf, 0, (size_t)bufsize);
600 while( !berr && padsize > 0 ) {
601 bytestowrite= (int)MIN(bufsize, padsize);
602 berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite;
603 padsize -= bytestowrite;
604 }
605
606 return berr;
607}
608
609static void do_setrattr(char *name, uint16 attr, int set)
610{
611 uint16 oldattr;
612
613 if (!NT_STATUS_IS_OK(cli_getatr(cli, name, &oldattr, NULL, NULL))) {
614 return;
615 }
616
617 if (set == ATTRSET) {
618 attr |= oldattr;
619 } else {
620 attr = oldattr & ~attr;
621 }
622
623 if (!NT_STATUS_IS_OK(cli_setatr(cli, name, attr, 0))) {
624 DEBUG(1,("setatr failed: %s\n", cli_errstr(cli)));
625 }
626}
627
628/****************************************************************************
629append one remote file to the tar file
630***************************************************************************/
631
632static NTSTATUS do_atar(const char *rname_in, char *lname,
633 struct file_info *finfo1)
634{
635 uint16_t fnum = (uint16_t)-1;
636 uint64_t nread=0;
637 char ftype;
638 file_info2 finfo;
639 bool shallitime=True;
640 char *data = NULL;
641 int read_size = 65520;
642 int datalen=0;
643 char *rname = NULL;
644 TALLOC_CTX *ctx = talloc_stackframe();
645 NTSTATUS status = NT_STATUS_OK;
646 struct timespec tp_start;
647
648 clock_gettime_mono(&tp_start);
649
650 data = SMB_MALLOC_ARRAY(char, read_size);
651 if (!data) {
652 DEBUG(0,("do_atar: out of memory.\n"));
653 status = NT_STATUS_NO_MEMORY;
654 goto cleanup;
655 }
656
657 ftype = '0'; /* An ordinary file ... */
658
659 ZERO_STRUCT(finfo);
660
661 finfo.size = finfo1 -> size;
662 finfo.mode = finfo1 -> mode;
663 finfo.uid = finfo1 -> uid;
664 finfo.gid = finfo1 -> gid;
665 finfo.mtime_ts = finfo1 -> mtime_ts;
666 finfo.atime_ts = finfo1 -> atime_ts;
667 finfo.ctime_ts = finfo1 -> ctime_ts;
668
669 if (dry_run) {
670 DEBUG(3,("skipping file %s of size %12.0f bytes\n", finfo1->name,
671 (double)finfo.size));
672 shallitime=0;
673 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
674 ntarf++;
675 goto cleanup;
676 }
677
678 rname = clean_name(ctx, rname_in);
679 if (!rname) {
680 status = NT_STATUS_NO_MEMORY;
681 goto cleanup;
682 }
683
684 status = cli_open(cli, rname, O_RDONLY, DENY_NONE, &fnum);
685 if (!NT_STATUS_IS_OK(status)) {
686 DEBUG(0,("%s opening remote file %s (%s)\n",
687 cli_errstr(cli),rname, client_get_cur_dir()));
688 goto cleanup;
689 }
690
691 finfo.name = string_create_s(strlen(rname));
692 if (finfo.name == NULL) {
693 DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n"));
694 status = NT_STATUS_NO_MEMORY;
695 goto cleanup;
696 }
697
698 safe_strcpy(finfo.name,rname, strlen(rname));
699
700 DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
701
702 if (tar_inc && !(finfo.mode & FILE_ATTRIBUTE_ARCHIVE)) {
703 DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
704 shallitime=0;
705 } else if (!tar_system && (finfo.mode & FILE_ATTRIBUTE_SYSTEM)) {
706 DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
707 shallitime=0;
708 } else if (!tar_hidden && (finfo.mode & FILE_ATTRIBUTE_HIDDEN)) {
709 DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
710 shallitime=0;
711 } else {
712 bool wrote_tar_header = False;
713
714 DEBUG(3,("getting file %s of size %.0f bytes as a tar file %s",
715 finfo.name, (double)finfo.size, lname));
716
717 do {
718
719 DEBUG(3,("nread=%.0f\n",(double)nread));
720
721 datalen = cli_read(cli, fnum, data, nread, read_size);
722
723 if (datalen == -1) {
724 DEBUG(0,("Error reading file %s : %s\n", rname, cli_errstr(cli)));
725 status = cli_nt_error(cli);
726 break;
727 }
728
729 nread += datalen;
730
731 /* Only if the first read succeeds, write out the tar header. */
732 if (!wrote_tar_header) {
733 /* write a tar header, don't bother with mode - just set to 100644 */
734 writetarheader(tarhandle, rname, finfo.size,
735 finfo.mtime_ts.tv_sec, "100644 \0", ftype);
736 wrote_tar_header = True;
737 }
738
739 /* if file size has increased since we made file size query, truncate
740 read so tar header for this file will be correct.
741 */
742
743 if (nread > finfo.size) {
744 datalen -= nread - finfo.size;
745 DEBUG(0,("File size change - truncating %s to %.0f bytes\n",
746 finfo.name, (double)finfo.size));
747 }
748
749 /* add received bits of file to buffer - dotarbuf will
750 * write out in 512 byte intervals */
751
752 if (dotarbuf(tarhandle,data,datalen) != datalen) {
753 DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
754 status = map_nt_error_from_unix(errno);
755 break;
756 }
757
758 if ( (datalen == 0) && (finfo.size != 0) ) {
759 status = NT_STATUS_UNSUCCESSFUL;
760 DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
761 break;
762 }
763
764 datalen=0;
765 } while ( nread < finfo.size );
766
767 if (wrote_tar_header) {
768 /* pad tar file with zero's if we couldn't get entire file */
769 if (nread < finfo.size) {
770 DEBUG(0, ("Didn't get entire file. size=%.0f, nread=%d\n",
771 (double)finfo.size, (int)nread));
772 if (padit(data, (uint64_t)sizeof(data), finfo.size - nread)) {
773 status = map_nt_error_from_unix(errno);
774 DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
775 }
776 }
777
778 /* round tar file to nearest block */
779 if (finfo.size % TBLOCK)
780 dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
781
782 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
783 ntarf++;
784 } else {
785 DEBUG(4, ("skipping %s - initial read failed (file was locked ?)\n", finfo.name));
786 shallitime=0;
787 status = NT_STATUS_UNSUCCESSFUL;
788 }
789 }
790
791 cli_close(cli, fnum);
792 fnum = -1;
793
794 if (shallitime) {
795 struct timespec tp_end;
796 int this_time;
797
798 /* if shallitime is true then we didn't skip */
799 if (tar_reset && !dry_run)
800 (void) do_setrattr(finfo.name, FILE_ATTRIBUTE_ARCHIVE, ATTRRESET);
801
802 clock_gettime_mono(&tp_end);
803 this_time = (tp_end.tv_sec - tp_start.tv_sec)*1000 + (tp_end.tv_nsec - tp_start.tv_nsec)/1000000;
804 get_total_time_ms += this_time;
805 get_total_size += finfo.size;
806
807 if (tar_noisy) {
808 DEBUG(0, ("%12.0f (%7.1f kb/s) %s\n",
809 (double)finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
810 finfo.name));
811 }
812
813 /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
814 DEBUG(3,("(%g kb/s) (average %g kb/s)\n",
815 finfo.size / MAX(0.001, (1.024*this_time)),
816 get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
817 }
818
819 cleanup:
820
821 if (fnum != (uint16_t)-1) {
822 cli_close(cli, fnum);
823 fnum = -1;
824 }
825 TALLOC_FREE(ctx);
826 SAFE_FREE(data);
827 return status;
828}
829
830/****************************************************************************
831Append single file to tar file (or not)
832***************************************************************************/
833
834static NTSTATUS do_tar(struct cli_state *cli_state, struct file_info *finfo,
835 const char *dir)
836{
837 TALLOC_CTX *ctx = talloc_stackframe();
838 NTSTATUS status = NT_STATUS_OK;
839
840 if (strequal(finfo->name,"..") || strequal(finfo->name,".")) {
841 status = NT_STATUS_OK;
842 goto cleanup;
843 }
844
845 /* Is it on the exclude list ? */
846 if (!tar_excl && clipn) {
847 char *exclaim;
848
849 DEBUG(5, ("Excl: strlen(cur_dir) = %d\n", (int)strlen(client_get_cur_dir())));
850
851 exclaim = talloc_asprintf(ctx,
852 "%s\\%s",
853 client_get_cur_dir(),
854 finfo->name);
855 if (!exclaim) {
856 status = NT_STATUS_NO_MEMORY;
857 goto cleanup;
858 }
859
860 DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
861
862 if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
863 (tar_re_search && mask_match_list(exclaim, cliplist, clipn, True))) {
864 DEBUG(3,("Skipping file %s\n", exclaim));
865 TALLOC_FREE(exclaim);
866 status = NT_STATUS_OK;
867 goto cleanup;
868 }
869 TALLOC_FREE(exclaim);
870 }
871
872 if (finfo->mode & FILE_ATTRIBUTE_DIRECTORY) {
873 char *saved_curdir = NULL;
874 char *new_cd = NULL;
875 char *mtar_mask = NULL;
876
877 saved_curdir = talloc_strdup(ctx, client_get_cur_dir());
878 if (!saved_curdir) {
879 status = NT_STATUS_NO_MEMORY;
880 goto cleanup;
881 }
882
883 DEBUG(5, ("strlen(cur_dir)=%d, \
884strlen(finfo->name)=%d\nname=%s,cur_dir=%s\n",
885 (int)strlen(saved_curdir),
886 (int)strlen(finfo->name), finfo->name, saved_curdir));
887
888 new_cd = talloc_asprintf(ctx,
889 "%s%s\\",
890 client_get_cur_dir(),
891 finfo->name);
892 if (!new_cd) {
893 status = NT_STATUS_NO_MEMORY;
894 goto cleanup;
895 }
896 client_set_cur_dir(new_cd);
897
898 DEBUG(5, ("Writing a dir, Name = %s\n", client_get_cur_dir()));
899
900 /* write a tar directory, don't bother with mode - just
901 * set it to 40755 */
902 writetarheader(tarhandle, client_get_cur_dir(), 0,
903 finfo->mtime_ts.tv_sec, "040755 \0", '5');
904 if (tar_noisy) {
905 DEBUG(0,(" directory %s\n",
906 client_get_cur_dir()));
907 }
908 ntarf++; /* Make sure we have a file on there */
909 mtar_mask = talloc_asprintf(ctx,
910 "%s*",
911 client_get_cur_dir());
912 if (!mtar_mask) {
913 status = NT_STATUS_NO_MEMORY;
914 goto cleanup;
915 }
916 DEBUG(5, ("Doing list with mtar_mask: %s\n", mtar_mask));
917 do_list(mtar_mask, attribute, do_tar, False, True);
918 client_set_cur_dir(saved_curdir);
919 TALLOC_FREE(saved_curdir);
920 TALLOC_FREE(new_cd);
921 TALLOC_FREE(mtar_mask);
922 } else {
923 char *rname = talloc_asprintf(ctx,
924 "%s%s",
925 client_get_cur_dir(),
926 finfo->name);
927 if (!rname) {
928 status = NT_STATUS_NO_MEMORY;
929 goto cleanup;
930 }
931 status = do_atar(rname,finfo->name,finfo);
932 TALLOC_FREE(rname);
933 }
934
935 cleanup:
936 TALLOC_FREE(ctx);
937 return status;
938}
939
940/****************************************************************************
941Convert from UNIX to DOS file names
942***************************************************************************/
943
944static void unfixtarname(char *tptr, char *fp, int l, bool first)
945{
946 /* remove '.' from start of file name, convert from unix /'s to
947 * dos \'s in path. Kill any absolute path names. But only if first!
948 */
949
950 DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
951
952 if (first) {
953 if (*fp == '.') {
954 fp++;
955 l--;
956 }
957 if (*fp == '\\' || *fp == '/') {
958 fp++;
959 l--;
960 }
961 }
962
963 safe_strcpy(tptr, fp, l);
964 string_replace(tptr, '/', '\\');
965}
966
967/****************************************************************************
968Move to the next block in the buffer, which may mean read in another set of
969blocks. FIXME, we should allow more than one block to be skipped.
970****************************************************************************/
971
972static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
973{
974 int bufread, total = 0;
975
976 DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp));
977 *bufferp += TBLOCK;
978 total = TBLOCK;
979
980 if (*bufferp >= (ltarbuf + bufsiz)) {
981
982 DEBUG(5, ("Reading more data into ltarbuf ...\n"));
983
984 /*
985 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>
986 * Fixes bug where read can return short if coming from
987 * a pipe.
988 */
989
990 bufread = read(tarhandle, ltarbuf, bufsiz);
991 total = bufread;
992
993 while (total < bufsiz) {
994 if (bufread < 0) { /* An error, return false */
995 return (total > 0 ? -2 : bufread);
996 }
997 if (bufread == 0) {
998 if (total <= 0) {
999 return -2;
1000 }
1001 break;
1002 }
1003 bufread = read(tarhandle, &ltarbuf[total], bufsiz - total);
1004 total += bufread;
1005 }
1006
1007 DEBUG(5, ("Total bytes read ... %i\n", total));
1008
1009 *bufferp = ltarbuf;
1010 }
1011
1012 return(total);
1013}
1014
1015/* Skip a file, even if it includes a long file name? */
1016static int skip_file(int skipsize)
1017{
1018 int dsize = skipsize;
1019
1020 DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
1021
1022 /* FIXME, we should skip more than one block at a time */
1023
1024 while (dsize > 0) {
1025 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1026 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1027 return(False);
1028 }
1029 dsize -= TBLOCK;
1030 }
1031
1032 return(True);
1033}
1034
1035/*************************************************************
1036 Get a file from the tar file and store it.
1037 When this is called, tarbuf already contains the first
1038 file block. This is a bit broken & needs fixing.
1039**************************************************************/
1040
1041static int get_file(file_info2 finfo)
1042{
1043 uint16_t fnum = (uint16_t) -1;
1044 int dsize = 0, bpos = 0;
1045 uint64_t rsize = 0, pos = 0;
1046 NTSTATUS status;
1047
1048 DEBUG(5, ("get_file: file: %s, size %.0f\n", finfo.name, (double)finfo.size));
1049
1050 if (!ensurepath(finfo.name)) {
1051 DEBUG(0, ("abandoning restore\n"));
1052 return False;
1053 }
1054
1055 status = cli_open(cli, finfo.name, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE, &fnum);
1056 if (!NT_STATUS_IS_OK(status)) {
1057 DEBUG(0, ("abandoning restore\n"));
1058 return False;
1059 }
1060
1061 /* read the blocks from the tar file and write to the remote file */
1062
1063 rsize = finfo.size; /* This is how much to write */
1064
1065 while (rsize > 0) {
1066
1067 /* We can only write up to the end of the buffer */
1068 dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, 65520); /* Calculate the size to write */
1069 dsize = MIN(dsize, rsize); /* Should be only what is left */
1070 DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos));
1071
1072 status = cli_writeall(cli, fnum, 0,
1073 (uint8_t *)(buffer_p + bpos), pos,
1074 dsize, NULL);
1075 if (!NT_STATUS_IS_OK(status)) {
1076 DEBUG(0, ("Error writing remote file: %s\n",
1077 nt_errstr(status)));
1078 return 0;
1079 }
1080
1081 rsize -= dsize;
1082 pos += dsize;
1083
1084 /* Now figure out how much to move in the buffer */
1085
1086 /* FIXME, we should skip more than one block at a time */
1087
1088 /* First, skip any initial part of the part written that is left over */
1089 /* from the end of the first TBLOCK */
1090
1091 if ((bpos) && ((bpos + dsize) >= TBLOCK)) {
1092 dsize -= (TBLOCK - bpos); /* Get rid of the end of the first block */
1093 bpos = 0;
1094
1095 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) { /* and skip the block */
1096 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1097 return False;
1098 }
1099 }
1100
1101 /*
1102 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>.
1103 * If the file being extracted is an exact multiple of
1104 * TBLOCK bytes then we don't want to extract the next
1105 * block from the tarfile here, as it will be done in
1106 * the caller of get_file().
1107 */
1108
1109 while (((rsize != 0) && (dsize >= TBLOCK)) ||
1110 ((rsize == 0) && (dsize > TBLOCK))) {
1111
1112 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1113 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1114 return False;
1115 }
1116
1117 dsize -= TBLOCK;
1118 }
1119 bpos = dsize;
1120 }
1121
1122 /* Now close the file ... */
1123
1124 if (!NT_STATUS_IS_OK(cli_close(cli, fnum))) {
1125 DEBUG(0, ("Error %s closing remote file\n",
1126 cli_errstr(cli)));
1127 return(False);
1128 }
1129
1130 /* Now we update the creation date ... */
1131 DEBUG(5, ("Updating creation date on %s\n", finfo.name));
1132
1133 if (!NT_STATUS_IS_OK(cli_setatr(cli, finfo.name, finfo.mode, finfo.mtime_ts.tv_sec))) {
1134 if (tar_real_noisy) {
1135 DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
1136 /*return(False); */ /* Ignore, as Win95 does not allow changes */
1137 }
1138 }
1139
1140 ntarf++;
1141 DEBUG(0, ("restore tar file %s of size %.0f bytes\n", finfo.name, (double)finfo.size));
1142 return(True);
1143}
1144
1145/* Create a directory. We just ensure that the path exists and return as there
1146 is no file associated with a directory
1147*/
1148static int get_dir(file_info2 finfo)
1149{
1150 DEBUG(0, ("restore directory %s\n", finfo.name));
1151
1152 if (!ensurepath(finfo.name)) {
1153 DEBUG(0, ("Problems creating directory\n"));
1154 return(False);
1155 }
1156 ntarf++;
1157 return(True);
1158}
1159
1160/* Get a file with a long file name ... first file has file name, next file
1161 has the data. We only want the long file name, as the loop in do_tarput
1162 will deal with the rest.
1163*/
1164static char *get_longfilename(file_info2 finfo)
1165{
1166 /* finfo.size here is the length of the filename as written by the "/./@LongLink" name
1167 * header call. */
1168 int namesize = finfo.size + strlen(client_get_cur_dir()) + 2;
1169 char *longname = (char *)SMB_MALLOC(namesize);
1170 int offset = 0, left = finfo.size;
1171 bool first = True;
1172
1173 DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
1174 DEBUG(5, ("Len = %.0f\n", (double)finfo.size));
1175
1176 if (longname == NULL) {
1177 DEBUG(0, ("could not allocate buffer of size %d for longname\n", namesize));
1178 return(NULL);
1179 }
1180
1181 /* First, add cur_dir to the long file name */
1182
1183 if (strlen(client_get_cur_dir()) > 0) {
1184 strncpy(longname, client_get_cur_dir(), namesize);
1185 offset = strlen(client_get_cur_dir());
1186 }
1187
1188 /* Loop through the blocks picking up the name */
1189
1190 while (left > 0) {
1191 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1192 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1193 SAFE_FREE(longname);
1194 return(NULL);
1195 }
1196
1197 unfixtarname(longname + offset, buffer_p, MIN(TBLOCK, finfo.size), first--);
1198 DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
1199
1200 offset += TBLOCK;
1201 left -= TBLOCK;
1202 }
1203
1204 return(longname);
1205}
1206
1207static void do_tarput(void)
1208{
1209 file_info2 finfo;
1210 struct timespec tp_start;
1211 char *longfilename = NULL, linkflag;
1212 int skip = False;
1213
1214 ZERO_STRUCT(finfo);
1215
1216 clock_gettime_mono(&tp_start);
1217 DEBUG(5, ("RJS do_tarput called ...\n"));
1218
1219 buffer_p = tarbuf + tbufsiz; /* init this to force first read */
1220
1221 /* Now read through those files ... */
1222 while (True) {
1223 /* Get us to the next block, or the first block first time around */
1224 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1225 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1226 SAFE_FREE(longfilename);
1227 return;
1228 }
1229
1230 DEBUG(5, ("Reading the next header ...\n"));
1231
1232 switch (readtarheader((union hblock *) buffer_p,
1233 &finfo, client_get_cur_dir())) {
1234 case -2: /* Hmm, not good, but not fatal */
1235 DEBUG(0, ("Skipping %s...\n", finfo.name));
1236 if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) && !skip_file(finfo.size)) {
1237 DEBUG(0, ("Short file, bailing out...\n"));
1238 SAFE_FREE(longfilename);
1239 return;
1240 }
1241 break;
1242
1243 case -1:
1244 DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
1245 SAFE_FREE(longfilename);
1246 return;
1247
1248 case 0: /* chksum is zero - looks like an EOF */
1249 DEBUG(0, ("tar: restored %d files and directories\n", ntarf));
1250 SAFE_FREE(longfilename);
1251 return; /* Hmmm, bad here ... */
1252
1253 default:
1254 /* No action */
1255 break;
1256 }
1257
1258 /* Now, do we have a long file name? */
1259 if (longfilename != NULL) {
1260 SAFE_FREE(finfo.name); /* Free the space already allocated */
1261 finfo.name = longfilename;
1262 longfilename = NULL;
1263 }
1264
1265 /* Well, now we have a header, process the file ... */
1266 /* Should we skip the file? We have the long name as well here */
1267 skip = clipn && ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl) ||
1268 (tar_re_search && mask_match_list(finfo.name, cliplist, clipn, True)));
1269
1270 DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
1271 if (skip) {
1272 skip_file(finfo.size);
1273 continue;
1274 }
1275
1276 /* We only get this far if we should process the file */
1277 linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
1278 switch (linkflag) {
1279 case '0': /* Should use symbolic names--FIXME */
1280 /*
1281 * Skip to the next block first, so we can get the file, FIXME, should
1282 * be in get_file ...
1283 * The 'finfo.size != 0' fix is from Bob Boehmer <boehmer@worldnet.att.net>
1284 * Fixes bug where file size in tarfile is zero.
1285 */
1286 if ((finfo.size != 0) && next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1287 DEBUG(0, ("Short file, bailing out...\n"));
1288 return;
1289 }
1290 if (!get_file(finfo)) {
1291 DEBUG(0, ("Abandoning restore\n"));
1292 return;
1293 }
1294 break;
1295 case '5':
1296 if (!get_dir(finfo)) {
1297 DEBUG(0, ("Abandoning restore \n"));
1298 return;
1299 }
1300 break;
1301 case 'L':
1302 SAFE_FREE(longfilename);
1303 longfilename = get_longfilename(finfo);
1304 if (!longfilename) {
1305 DEBUG(0, ("abandoning restore\n"));
1306 return;
1307 }
1308 DEBUG(5, ("Long file name: %s\n", longfilename));
1309 break;
1310
1311 default:
1312 skip_file(finfo.size); /* Don't handle these yet */
1313 break;
1314 }
1315 }
1316}
1317
1318/*
1319 * samba interactive commands
1320 */
1321
1322/****************************************************************************
1323Blocksize command
1324***************************************************************************/
1325
1326int cmd_block(void)
1327{
1328 TALLOC_CTX *ctx = talloc_tos();
1329 char *buf;
1330 int block;
1331
1332 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1333 DEBUG(0, ("blocksize <n>\n"));
1334 return 1;
1335 }
1336
1337 block=atoi(buf);
1338 if (block < 0 || block > 65535) {
1339 DEBUG(0, ("blocksize out of range"));
1340 return 1;
1341 }
1342
1343 blocksize=block;
1344 DEBUG(2,("blocksize is now %d\n", blocksize));
1345 return 0;
1346}
1347
1348/****************************************************************************
1349command to set incremental / reset mode
1350***************************************************************************/
1351
1352int cmd_tarmode(void)
1353{
1354 TALLOC_CTX *ctx = talloc_tos();
1355 char *buf;
1356
1357 while (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1358 if (strequal(buf, "full"))
1359 tar_inc=False;
1360 else if (strequal(buf, "inc"))
1361 tar_inc=True;
1362 else if (strequal(buf, "reset"))
1363 tar_reset=True;
1364 else if (strequal(buf, "noreset"))
1365 tar_reset=False;
1366 else if (strequal(buf, "system"))
1367 tar_system=True;
1368 else if (strequal(buf, "nosystem"))
1369 tar_system=False;
1370 else if (strequal(buf, "hidden"))
1371 tar_hidden=True;
1372 else if (strequal(buf, "nohidden"))
1373 tar_hidden=False;
1374 else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
1375 tar_noisy=True;
1376 else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
1377 tar_noisy=False;
1378 else
1379 DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
1380 TALLOC_FREE(buf);
1381 }
1382
1383 DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
1384 tar_inc ? "incremental" : "full",
1385 tar_system ? "system" : "nosystem",
1386 tar_hidden ? "hidden" : "nohidden",
1387 tar_reset ? "reset" : "noreset",
1388 tar_noisy ? "verbose" : "quiet"));
1389 return 0;
1390}
1391
1392/****************************************************************************
1393Feeble attrib command
1394***************************************************************************/
1395
1396int cmd_setmode(void)
1397{
1398 TALLOC_CTX *ctx = talloc_tos();
1399 char *q;
1400 char *buf;
1401 char *fname = NULL;
1402 uint16 attra[2];
1403 int direct=1;
1404
1405 attra[0] = attra[1] = 0;
1406
1407 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1408 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1409 return 1;
1410 }
1411
1412 fname = talloc_asprintf(ctx,
1413 "%s%s",
1414 client_get_cur_dir(),
1415 buf);
1416 if (!fname) {
1417 return 1;
1418 }
1419
1420 while (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1421 q=buf;
1422
1423 while(*q) {
1424 switch (*q++) {
1425 case '+':
1426 direct=1;
1427 break;
1428 case '-':
1429 direct=0;
1430 break;
1431 case 'r':
1432 attra[direct]|=FILE_ATTRIBUTE_READONLY;
1433 break;
1434 case 'h':
1435 attra[direct]|=FILE_ATTRIBUTE_HIDDEN;
1436 break;
1437 case 's':
1438 attra[direct]|=FILE_ATTRIBUTE_SYSTEM;
1439 break;
1440 case 'a':
1441 attra[direct]|=FILE_ATTRIBUTE_ARCHIVE;
1442 break;
1443 default:
1444 DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1445 return 1;
1446 }
1447 }
1448 }
1449
1450 if (attra[ATTRSET]==0 && attra[ATTRRESET]==0) {
1451 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1452 return 1;
1453 }
1454
1455 DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1456 do_setrattr(fname, attra[ATTRSET], ATTRSET);
1457 do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
1458 return 0;
1459}
1460
1461/**
1462 Convert list of tokens to array; dependent on above routine.
1463 Uses the global cmd_ptr from above - bit of a hack.
1464**/
1465
1466static char **toktocliplist(int *ctok, const char *sep)
1467{
1468 char *s=(char *)cmd_ptr;
1469 int ictok=0;
1470 char **ret, **iret;
1471
1472 if (!sep)
1473 sep = " \t\n\r";
1474
1475 while(*s && strchr_m(sep,*s))
1476 s++;
1477
1478 /* nothing left? */
1479 if (!*s)
1480 return(NULL);
1481
1482 do {
1483 ictok++;
1484 while(*s && (!strchr_m(sep,*s)))
1485 s++;
1486 while(*s && strchr_m(sep,*s))
1487 *s++=0;
1488 } while(*s);
1489
1490 *ctok=ictok;
1491 s=(char *)cmd_ptr;
1492
1493 if (!(ret=iret=SMB_MALLOC_ARRAY(char *,ictok+1)))
1494 return NULL;
1495
1496 while(ictok--) {
1497 *iret++=s;
1498 if (ictok > 0) {
1499 while(*s++)
1500 ;
1501 while(!*s)
1502 s++;
1503 }
1504 }
1505
1506 ret[*ctok] = NULL;
1507 return ret;
1508}
1509
1510/****************************************************************************
1511Principal command for creating / extracting
1512***************************************************************************/
1513
1514int cmd_tar(void)
1515{
1516 TALLOC_CTX *ctx = talloc_tos();
1517 char *buf;
1518 char **argl = NULL;
1519 int argcl = 0;
1520 int ret;
1521
1522 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1523 DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
1524 return 1;
1525 }
1526
1527 argl=toktocliplist(&argcl, NULL);
1528 if (!tar_parseargs(argcl, argl, buf, 0)) {
1529 SAFE_FREE(argl);
1530 return 1;
1531 }
1532
1533 ret = process_tar();
1534 SAFE_FREE(argl);
1535 return ret;
1536}
1537
1538/****************************************************************************
1539Command line (option) version
1540***************************************************************************/
1541
1542int process_tar(void)
1543{
1544 TALLOC_CTX *ctx = talloc_tos();
1545 int rc = 0;
1546 initarbuf();
1547 switch(tar_type) {
1548 case 'x':
1549
1550#if 0
1551 do_tarput2();
1552#else
1553 do_tarput();
1554#endif
1555 SAFE_FREE(tarbuf);
1556 close(tarhandle);
1557 break;
1558 case 'r':
1559 case 'c':
1560 if (clipn && tar_excl) {
1561 int i;
1562 char *tarmac = NULL;
1563
1564 for (i=0; i<clipn; i++) {
1565 DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
1566
1567 if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1568 *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1569 }
1570
1571 if (strrchr_m(cliplist[i], '\\')) {
1572 char *p;
1573 char saved_char;
1574 char *saved_dir = talloc_strdup(ctx,
1575 client_get_cur_dir());
1576 if (!saved_dir) {
1577 return 1;
1578 }
1579
1580 if (*cliplist[i]=='\\') {
1581 tarmac = talloc_strdup(ctx,
1582 cliplist[i]);
1583 } else {
1584 tarmac = talloc_asprintf(ctx,
1585 "%s%s",
1586 client_get_cur_dir(),
1587 cliplist[i]);
1588 }
1589 if (!tarmac) {
1590 return 1;
1591 }
1592 /*
1593 * Strip off the last \\xxx
1594 * xxx element of tarmac to set
1595 * it as current directory.
1596 */
1597 p = strrchr_m(tarmac, '\\');
1598 if (!p) {
1599 return 1;
1600 }
1601 saved_char = p[1];
1602 p[1] = '\0';
1603
1604 client_set_cur_dir(tarmac);
1605
1606 /*
1607 * Restore the character we
1608 * just replaced to
1609 * put the pathname
1610 * back as it was.
1611 */
1612 p[1] = saved_char;
1613
1614 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1615 do_list(tarmac,attribute,do_tar, False, True);
1616
1617 client_set_cur_dir(saved_dir);
1618
1619 TALLOC_FREE(saved_dir);
1620 TALLOC_FREE(tarmac);
1621 } else {
1622 tarmac = talloc_asprintf(ctx,
1623 "%s%s",
1624 client_get_cur_dir(),
1625 cliplist[i]);
1626 if (!tarmac) {
1627 return 1;
1628 }
1629 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1630 do_list(tarmac,attribute,do_tar, False, True);
1631 TALLOC_FREE(tarmac);
1632 }
1633 }
1634 } else {
1635 char *mask = talloc_asprintf(ctx,
1636 "%s\\*",
1637 client_get_cur_dir());
1638 if (!mask) {
1639 return 1;
1640 }
1641 DEBUG(5, ("process_tar, do_list with mask: %s\n", mask));
1642 do_list(mask,attribute,do_tar,False, True);
1643 TALLOC_FREE(mask);
1644 }
1645
1646 if (ntarf) {
1647 dotareof(tarhandle);
1648 }
1649 close(tarhandle);
1650 SAFE_FREE(tarbuf);
1651
1652 DEBUG(0, ("tar: dumped %d files and directories\n", ntarf));
1653 DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf));
1654 break;
1655 }
1656
1657 if (must_free_cliplist) {
1658 int i;
1659 for (i = 0; i < clipn; ++i) {
1660 SAFE_FREE(cliplist[i]);
1661 }
1662 SAFE_FREE(cliplist);
1663 cliplist = NULL;
1664 clipn = 0;
1665 must_free_cliplist = False;
1666 }
1667 return rc;
1668}
1669
1670/****************************************************************************
1671Find a token (filename) in a clip list
1672***************************************************************************/
1673
1674static int clipfind(char **aret, int ret, char *tok)
1675{
1676 if (aret==NULL)
1677 return 0;
1678
1679 /* ignore leading slashes or dots in token */
1680 while(strchr_m("/\\.", *tok))
1681 tok++;
1682
1683 while(ret--) {
1684 char *pkey=*aret++;
1685
1686 /* ignore leading slashes or dots in list */
1687 while(strchr_m("/\\.", *pkey))
1688 pkey++;
1689
1690 if (!strslashcmp(pkey, tok))
1691 return 1;
1692 }
1693 return 0;
1694}
1695
1696/****************************************************************************
1697Read list of files to include from the file and initialize cliplist
1698accordingly.
1699***************************************************************************/
1700
1701static int read_inclusion_file(char *filename)
1702{
1703 XFILE *inclusion = NULL;
1704 char buf[PATH_MAX + 1];
1705 char *inclusion_buffer = NULL;
1706 int inclusion_buffer_size = 0;
1707 int inclusion_buffer_sofar = 0;
1708 char *p;
1709 char *tmpstr;
1710 int i;
1711 int error = 0;
1712
1713 clipn = 0;
1714 buf[PATH_MAX] = '\0'; /* guarantee null-termination */
1715 if ((inclusion = x_fopen(filename, O_RDONLY, 0)) == NULL) {
1716 /* XXX It would be better to include a reason for failure, but without
1717 * autoconf, it's hard to use strerror, sys_errlist, etc.
1718 */
1719 DEBUG(0,("Unable to open inclusion file %s\n", filename));
1720 return 0;
1721 }
1722
1723 while ((! error) && (x_fgets(buf, sizeof(buf)-1, inclusion))) {
1724 if (inclusion_buffer == NULL) {
1725 inclusion_buffer_size = 1024;
1726 if ((inclusion_buffer = (char *)SMB_MALLOC(inclusion_buffer_size)) == NULL) {
1727 DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1728 error = 1;
1729 break;
1730 }
1731 }
1732
1733 if (buf[strlen(buf)-1] == '\n') {
1734 buf[strlen(buf)-1] = '\0';
1735 }
1736
1737 if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1738 inclusion_buffer_size *= 2;
1739 inclusion_buffer = (char *)SMB_REALLOC(inclusion_buffer,inclusion_buffer_size);
1740 if (!inclusion_buffer) {
1741 DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1742 inclusion_buffer_size));
1743 error = 1;
1744 break;
1745 }
1746 }
1747
1748 safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
1749 inclusion_buffer_sofar += strlen(buf) + 1;
1750 clipn++;
1751 }
1752 x_fclose(inclusion);
1753
1754 if (! error) {
1755 /* Allocate an array of clipn + 1 char*'s for cliplist */
1756 cliplist = SMB_MALLOC_ARRAY(char *, clipn + 1);
1757 if (cliplist == NULL) {
1758 DEBUG(0,("failure allocating memory for cliplist\n"));
1759 error = 1;
1760 } else {
1761 cliplist[clipn] = NULL;
1762 p = inclusion_buffer;
1763 for (i = 0; (! error) && (i < clipn); i++) {
1764 /* set current item to NULL so array will be null-terminated even if
1765 * malloc fails below. */
1766 cliplist[i] = NULL;
1767 if ((tmpstr = (char *)SMB_MALLOC(strlen(p)+1)) == NULL) {
1768 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
1769 error = 1;
1770 } else {
1771 unfixtarname(tmpstr, p, strlen(p) + 1, True);
1772 cliplist[i] = tmpstr;
1773 if ((p = strchr_m(p, '\000')) == NULL) {
1774 DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1775 abort();
1776 }
1777 }
1778 ++p;
1779 }
1780 must_free_cliplist = True;
1781 }
1782 }
1783
1784 SAFE_FREE(inclusion_buffer);
1785 if (error) {
1786 if (cliplist) {
1787 char **pp;
1788 /* We know cliplist is always null-terminated */
1789 for (pp = cliplist; *pp; ++pp) {
1790 SAFE_FREE(*pp);
1791 }
1792 SAFE_FREE(cliplist);
1793 cliplist = NULL;
1794 must_free_cliplist = False;
1795 }
1796 return 0;
1797 }
1798
1799 /* cliplist and its elements are freed at the end of process_tar. */
1800 return 1;
1801}
1802
1803/****************************************************************************
1804Parse tar arguments. Sets tar_type, tar_excl, etc.
1805***************************************************************************/
1806
1807int tar_parseargs(int argc, char *argv[], const char *Optarg, int Optind)
1808{
1809 int newOptind = Optind;
1810 char tar_clipfl='\0';
1811
1812 /* Reset back to defaults - could be from interactive version
1813 * reset mode and archive mode left as they are though
1814 */
1815 tar_type='\0';
1816 tar_excl=True;
1817 dry_run=False;
1818
1819 while (*Optarg) {
1820 switch(*Optarg++) {
1821 case 'c':
1822 tar_type='c';
1823 break;
1824 case 'x':
1825 if (tar_type=='c') {
1826 printf("Tar must be followed by only one of c or x.\n");
1827 return 0;
1828 }
1829 tar_type='x';
1830 break;
1831 case 'b':
1832 if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1833 DEBUG(0,("Option b must be followed by valid blocksize\n"));
1834 return 0;
1835 } else {
1836 Optind++;
1837 newOptind++;
1838 }
1839 break;
1840 case 'g':
1841 tar_inc=True;
1842 break;
1843 case 'N':
1844 if (Optind>=argc) {
1845 DEBUG(0,("Option N must be followed by valid file name\n"));
1846 return 0;
1847 } else {
1848 SMB_STRUCT_STAT stbuf;
1849
1850 if (sys_stat(argv[Optind], &stbuf,
1851 false) == 0) {
1852 newer_than = convert_timespec_to_time_t(
1853 stbuf.st_ex_mtime);
1854 DEBUG(1,("Getting files newer than %s",
1855 time_to_asc(newer_than)));
1856 newOptind++;
1857 Optind++;
1858 } else {
1859 DEBUG(0,("Error setting newer-than time\n"));
1860 return 0;
1861 }
1862 }
1863 break;
1864 case 'a':
1865 tar_reset=True;
1866 break;
1867 case 'q':
1868 tar_noisy=False;
1869 break;
1870 case 'I':
1871 if (tar_clipfl) {
1872 DEBUG(0,("Only one of I,X,F must be specified\n"));
1873 return 0;
1874 }
1875 tar_clipfl='I';
1876 break;
1877 case 'X':
1878 if (tar_clipfl) {
1879 DEBUG(0,("Only one of I,X,F must be specified\n"));
1880 return 0;
1881 }
1882 tar_clipfl='X';
1883 break;
1884 case 'F':
1885 if (tar_clipfl) {
1886 DEBUG(0,("Only one of I,X,F must be specified\n"));
1887 return 0;
1888 }
1889 tar_clipfl='F';
1890 break;
1891 case 'r':
1892 DEBUG(0, ("tar_re_search set\n"));
1893 tar_re_search = True;
1894 break;
1895 case 'n':
1896 if (tar_type == 'c') {
1897 DEBUG(0, ("dry_run set\n"));
1898 dry_run = True;
1899 } else {
1900 DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1901 return 0;
1902 }
1903 break;
1904 default:
1905 DEBUG(0,("Unknown tar option\n"));
1906 return 0;
1907 }
1908 }
1909
1910 if (!tar_type) {
1911 printf("Option T must be followed by one of c or x.\n");
1912 return 0;
1913 }
1914
1915 /* tar_excl is true if cliplist lists files to be included.
1916 * Both 'I' and 'F' mean include. */
1917 tar_excl=tar_clipfl!='X';
1918
1919 if (tar_clipfl=='F') {
1920 if (argc-Optind-1 != 1) {
1921 DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1922 return 0;
1923 }
1924 newOptind++;
1925 /* Optind points at the tar output file, Optind+1 at the inclusion file. */
1926 if (! read_inclusion_file(argv[Optind+1])) {
1927 return 0;
1928 }
1929 } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
1930 char *tmpstr;
1931 char **tmplist;
1932 int clipcount;
1933
1934 cliplist=argv+Optind+1;
1935 clipn=argc-Optind-1;
1936 clipcount = clipn;
1937
1938 if ((tmplist=SMB_MALLOC_ARRAY(char *,clipn)) == NULL) {
1939 DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n", clipn));
1940 return 0;
1941 }
1942
1943 for (clipcount = 0; clipcount < clipn; clipcount++) {
1944
1945 DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1946
1947 if ((tmpstr = (char *)SMB_MALLOC(strlen(cliplist[clipcount])+1)) == NULL) {
1948 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", clipcount));
1949 SAFE_FREE(tmplist);
1950 return 0;
1951 }
1952
1953 unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
1954 tmplist[clipcount] = tmpstr;
1955 DEBUG(5, ("Processed an item, %s\n", tmpstr));
1956
1957 DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1958 }
1959
1960 cliplist = tmplist;
1961 must_free_cliplist = True;
1962
1963 newOptind += clipn;
1964 }
1965
1966 if (Optind+1<argc && tar_re_search && tar_clipfl != 'F') {
1967 /* Doing regular expression seaches not from an inclusion file. */
1968 clipn=argc-Optind-1;
1969 cliplist=argv+Optind+1;
1970 newOptind += clipn;
1971 }
1972
1973 if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1974 /* Sets tar handle to either 0 or 1, as appropriate */
1975 tarhandle=(tar_type=='c');
1976 /*
1977 * Make sure that dbf points to stderr if we are using stdout for
1978 * tar output
1979 */
1980 if (tarhandle == 1) {
1981 setup_logging("smbclient", DEBUG_STDERR);
1982 }
1983 if (!argv[Optind]) {
1984 DEBUG(0,("Must specify tar filename\n"));
1985 return 0;
1986 }
1987 if (!strcmp(argv[Optind], "-")) {
1988 newOptind++;
1989 }
1990
1991 } else {
1992 if (tar_type=='c' && dry_run) {
1993 tarhandle=-1;
1994 } else if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1)
1995 || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0)) {
1996 DEBUG(0,("Error opening local file %s - %s\n", argv[Optind], strerror(errno)));
1997 return(0);
1998 }
1999 newOptind++;
2000 }
2001
2002 return newOptind;
2003}
Note: See TracBrowser for help on using the repository browser.