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

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

Samba Server: updated trunk to 3.6.0

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