docs: man ldbdel: Add missing meta data.
[Samba/gebeck_regimport.git] / source3 / client / clitar.c
blobd3525719f5e2449688302ceba10a631ff4950895
1 /*
2 Unix SMB/CIFS implementation.
3 Tar Extensions
4 Copyright (C) Ricky Poulten 1995-1998
5 Copyright (C) Richard Sharpe 1998
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.
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.
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/>.
20 /* The following changes developed by Richard Sharpe for Canon Information
21 Systems Research Australia (CISRA)
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:
31 -TcrX file.tar "*.(obj|exe)"
33 will skip all .obj and .exe files
37 #include "includes.h"
38 #include "system/filesys.h"
39 #include "clitar.h"
40 #include "client/client_proto.h"
41 #include "libsmb/libsmb.h"
43 static int clipfind(char **aret, int ret, char *tok);
45 typedef struct file_info_struct file_info2;
47 struct file_info_struct {
48 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 ... */
60 typedef struct {
61 file_info2 *top;
62 int items;
63 } stack;
65 #define SEPARATORS " \t\n\r"
66 extern time_t newer_than;
67 extern struct cli_state *cli;
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
74 static uint16 attribute = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
76 #ifndef CLIENT_TIMEOUT
77 #define CLIENT_TIMEOUT (30*1000)
78 #endif
80 static char *tarbuf, *buffer_p;
81 static int tp, ntarf, tbufsiz;
82 static double ttarf;
83 /* Incremental mode */
84 static bool tar_inc=False;
85 /* Reset archive bit */
86 static bool tar_reset=False;
87 /* Include / exclude mode (true=include, false=exclude) */
88 static bool tar_excl=True;
89 /* use regular expressions for search on file names */
90 static bool tar_re_search=False;
91 /* Do not dump anything, just calculate sizes */
92 static bool dry_run=False;
93 /* Dump files with System attribute */
94 static bool tar_system=True;
95 /* Dump files with Hidden attribute */
96 static bool tar_hidden=True;
97 /* Be noisy - make a catalogue */
98 static bool tar_noisy=True;
99 static bool tar_real_noisy=False; /* Don't want to be really noisy by default */
101 char tar_type='\0';
102 static char **cliplist=NULL;
103 static int clipn=0;
104 static bool must_free_cliplist = False;
105 extern char *cmd_ptr;
107 extern bool lowercase;
108 extern int get_total_time_ms;
109 extern int get_total_size;
111 static int blocksize=20;
112 static int tarhandle;
114 static void writetarheader(int f, const char *aname, uint64_t size, time_t mtime,
115 const char *amode, unsigned char ftype);
116 static NTSTATUS do_atar(const char *rname_in, char *lname,
117 struct file_info *finfo1);
118 static NTSTATUS do_tar(struct cli_state *cli_state, struct file_info *finfo,
119 const char *dir);
120 static void oct_it(uint64_t value, int ndgs, char *p);
121 static void fixtarname(char *tptr, const char *fp, size_t l);
122 static int dotarbuf(int f, char *b, int n);
123 static void dozerobuf(int f, int n);
124 static void dotareof(int f);
125 static void initarbuf(void);
127 /* restore functions */
128 static long readtarheader(union hblock *hb, file_info2 *finfo, const char *prefix);
129 static long unoct(char *p, int ndgs);
130 static void do_tarput(void);
131 static void unfixtarname(char *tptr, char *fp, int l, bool first);
134 * tar specific utitlities
137 /****************************************************************************
138 Write a tar header to buffer
139 ****************************************************************************/
141 static void writetarheader(int f, const char *aname, uint64_t size, time_t mtime,
142 const char *amode, unsigned char ftype)
144 union hblock hb;
145 int i, chk, l;
146 char *jp;
148 DEBUG(5, ("WriteTarHdr, Type = %c, Size= %.0f, Name = %s\n", ftype, (double)size, aname));
150 memset(hb.dummy, 0, sizeof(hb.dummy));
152 l=strlen(aname);
153 /* We will be prepending a '.' in fixtarheader so use +2 to
154 * take care of the . and terminating zero. JRA.
156 if (l+2 >= NAMSIZ) {
157 /* write a GNU tar style long header */
158 char *b;
159 b = (char *)SMB_MALLOC(l+TBLOCK+100);
160 if (!b) {
161 DEBUG(0,("out of memory\n"));
162 exit(1);
164 writetarheader(f, "/./@LongLink", l+2, 0, " 0 \0", 'L');
165 memset(b, 0, l+TBLOCK+100);
166 fixtarname(b, aname, l+2);
167 i = strlen(b)+1;
168 DEBUG(5, ("File name in tar file: %s, size=%d, \n", b, (int)strlen(b)));
169 dotarbuf(f, b, TBLOCK*(((i-1)/TBLOCK)+1));
170 SAFE_FREE(b);
173 fixtarname(hb.dbuf.name, aname, (l+2 >= NAMSIZ) ? NAMSIZ : l + 2);
175 if (lowercase)
176 (void)strlower_m(hb.dbuf.name);
178 /* write out a "standard" tar format header */
180 hb.dbuf.name[NAMSIZ-1]='\0';
181 strlcpy(hb.dbuf.mode, amode ? amode : "", sizeof(hb.dbuf.mode));
182 oct_it((uint64_t)0, 8, hb.dbuf.uid);
183 oct_it((uint64_t)0, 8, hb.dbuf.gid);
184 oct_it((uint64_t) size, 13, hb.dbuf.size);
185 if (size > (uint64_t)077777777777LL) {
186 /* This is a non-POSIX compatible extention to store files
187 greater than 8GB. */
189 memset(hb.dbuf.size, 0, 4);
190 hb.dbuf.size[0]=128;
191 for (i = 8; i; i--) {
192 hb.dbuf.size[i+3] = size & 0xff;
193 size >>= 8;
196 oct_it((uint64_t) mtime, 13, hb.dbuf.mtime);
197 memcpy(hb.dbuf.chksum, " ", sizeof(hb.dbuf.chksum));
198 memset(hb.dbuf.linkname, 0, NAMSIZ);
199 hb.dbuf.linkflag=ftype;
201 for (chk=0, i=sizeof(hb.dummy), jp=hb.dummy; --i>=0;)
202 chk+=(0xFF & *jp++);
204 oct_it((uint64_t) chk, 8, hb.dbuf.chksum);
205 hb.dbuf.chksum[6] = '\0';
207 (void) dotarbuf(f, hb.dummy, sizeof(hb.dummy));
210 /****************************************************************************
211 Read a tar header into a hblock structure, and validate
212 ***************************************************************************/
214 static long readtarheader(union hblock *hb, file_info2 *finfo, const char *prefix)
216 long chk, fchk;
217 int i;
218 char *jp;
221 * read in a "standard" tar format header - we're not that interested
222 * in that many fields, though
225 /* check the checksum */
226 for (chk=0, i=sizeof(hb->dummy), jp=hb->dummy; --i>=0;)
227 chk+=(0xFF & *jp++);
229 if (chk == 0)
230 return chk;
232 /* compensate for blanks in chksum header */
233 for (i=sizeof(hb->dbuf.chksum), jp=hb->dbuf.chksum; --i>=0;)
234 chk-=(0xFF & *jp++);
236 chk += ' ' * sizeof(hb->dbuf.chksum);
238 fchk=unoct(hb->dbuf.chksum, sizeof(hb->dbuf.chksum));
240 DEBUG(5, ("checksum totals chk=%ld fchk=%ld chksum=%s\n",
241 chk, fchk, hb->dbuf.chksum));
243 if (fchk != chk) {
244 DEBUG(0, ("checksums don't match %ld %ld\n", fchk, chk));
245 dump_data(5, (uint8 *)hb - TBLOCK, TBLOCK *3);
246 return -1;
249 if ((finfo->name = SMB_MALLOC(strlen(prefix) + strlen(hb -> dbuf.name) + 4)) == NULL) {
250 DEBUG(0, ("Out of space creating file_info2 for %s\n", hb -> dbuf.name));
251 return(-1);
254 strlcpy(finfo->name, prefix, strlen(prefix) + strlen(hb -> dbuf.name) + 4);
256 /* use l + 1 to do the null too; do prefix - prefcnt to zap leading slash */
257 unfixtarname(finfo->name + strlen(prefix), hb->dbuf.name,
258 strlen(hb->dbuf.name) + 1, True);
260 /* can't handle some links at present */
261 if ((hb->dbuf.linkflag != '0') && (hb -> dbuf.linkflag != '5')) {
262 if (hb->dbuf.linkflag == 0) {
263 DEBUG(6, ("Warning: NULL link flag (gnu tar archive ?) %s\n",
264 finfo->name));
265 } else {
266 if (hb -> dbuf.linkflag == 'L') { /* We have a longlink */
267 /* Do nothing here at the moment. do_tarput will handle this
268 as long as the longlink gets back to it, as it has to advance
269 the buffer pointer, etc */
270 } else {
271 DEBUG(0, ("this tar file appears to contain some kind \
272 of link other than a GNUtar Longlink - ignoring\n"));
273 return -2;
278 if ((unoct(hb->dbuf.mode, sizeof(hb->dbuf.mode)) & S_IFDIR) ||
279 (*(finfo->name+strlen(finfo->name)-1) == '\\')) {
280 finfo->mode=FILE_ATTRIBUTE_DIRECTORY;
281 } else {
282 finfo->mode=0; /* we don't care about mode at the moment, we'll
283 * just make it a regular file */
287 * Bug fix by richard@sj.co.uk
289 * REC: restore times correctly (as does tar)
290 * We only get the modification time of the file; set the creation time
291 * from the mod. time, and the access time to current time
293 finfo->mtime_ts = finfo->ctime_ts =
294 convert_time_t_to_timespec((time_t)strtol(hb->dbuf.mtime, NULL, 8));
295 finfo->atime_ts = convert_time_t_to_timespec(time(NULL));
296 if ((hb->dbuf.size[0] & 0xff) == 0x80) {
297 /* This is a non-POSIX compatible extention to extract files
298 greater than 8GB. */
299 finfo->size = 0;
300 for (i = 0; i < 8; i++) {
301 finfo->size <<= 8;
302 finfo->size |= hb->dbuf.size[i+4] & 0xff;
304 } else {
305 finfo->size = unoct(hb->dbuf.size, sizeof(hb->dbuf.size));
308 return True;
311 /****************************************************************************
312 Write out the tar buffer to tape or wherever
313 ****************************************************************************/
315 static int dotarbuf(int f, char *b, int n)
317 int fail=1, writ=n;
319 if (dry_run) {
320 return writ;
322 /* This routine and the next one should be the only ones that do write()s */
323 if (tp + n >= tbufsiz) {
324 int diff;
326 diff=tbufsiz-tp;
327 memcpy(tarbuf + tp, b, diff);
328 fail=fail && (1+sys_write(f, tarbuf, tbufsiz));
329 n-=diff;
330 b+=diff;
331 tp=0;
333 while (n >= tbufsiz) {
334 fail=fail && (1 + sys_write(f, b, tbufsiz));
335 n-=tbufsiz;
336 b+=tbufsiz;
340 if (n>0) {
341 memcpy(tarbuf+tp, b, n);
342 tp+=n;
345 return(fail ? writ : 0);
348 /****************************************************************************
349 Write zeros to buffer / tape
350 ****************************************************************************/
352 static void dozerobuf(int f, int n)
354 /* short routine just to write out n zeros to buffer -
355 * used to round files to nearest block
356 * and to do tar EOFs */
358 if (dry_run)
359 return;
361 if (n+tp >= tbufsiz) {
362 memset(tarbuf+tp, 0, tbufsiz-tp);
363 if (sys_write(f, tarbuf, tbufsiz) != tbufsiz) {
364 DEBUG(0, ("dozerobuf: sys_write fail\n"));
365 return;
367 memset(tarbuf, 0, (tp+=n-tbufsiz));
368 } else {
369 memset(tarbuf+tp, 0, n);
370 tp+=n;
374 /****************************************************************************
375 Malloc tape buffer
376 ****************************************************************************/
378 static void initarbuf(void)
380 /* initialize tar buffer */
381 tbufsiz=blocksize*TBLOCK;
382 tarbuf=(char *)SMB_MALLOC(tbufsiz); /* FIXME: We might not get the buffer */
384 /* reset tar buffer pointer and tar file counter and total dumped */
385 tp=0; ntarf=0; ttarf=0;
388 /****************************************************************************
389 Write two zero blocks at end of file
390 ****************************************************************************/
392 static void dotareof(int f)
394 SMB_STRUCT_STAT stbuf;
395 /* Two zero blocks at end of file, write out full buffer */
397 if (dry_run)
398 return;
400 (void) dozerobuf(f, TBLOCK);
401 (void) dozerobuf(f, TBLOCK);
403 if (sys_fstat(f, &stbuf, false) == -1) {
404 DEBUG(0, ("Couldn't stat file handle\n"));
405 return;
408 /* Could be a pipe, in which case S_ISREG should fail,
409 * and we should write out at full size */
410 if (tp > 0) {
411 size_t towrite = S_ISREG(stbuf.st_ex_mode) ? tp : tbufsiz;
412 if (sys_write(f, tarbuf, towrite) != towrite) {
413 DEBUG(0,("dotareof: sys_write fail\n"));
418 /****************************************************************************
419 (Un)mangle DOS pathname, make nonabsolute
420 ****************************************************************************/
422 static void fixtarname(char *tptr, const char *fp, size_t l)
424 /* add a '.' to start of file name, convert from ugly dos \'s in path
425 * to lovely unix /'s :-} */
426 *tptr++='.';
427 l--;
429 StrnCpy(tptr, fp, l-1);
430 string_replace(tptr, '\\', '/');
433 /****************************************************************************
434 Convert from decimal to octal string
435 ****************************************************************************/
437 static void oct_it (uint64_t value, int ndgs, char *p)
439 /* Converts long to octal string, pads with leading zeros */
441 /* skip final null, but do final space */
442 --ndgs;
443 p[--ndgs] = ' ';
445 /* Loop does at least one digit */
446 do {
447 p[--ndgs] = '0' + (char) (value & 7);
448 value >>= 3;
449 } while (ndgs > 0 && value != 0);
451 /* Do leading zeros */
452 while (ndgs > 0)
453 p[--ndgs] = '0';
456 /****************************************************************************
457 Convert from octal string to long
458 ***************************************************************************/
460 static long unoct(char *p, int ndgs)
462 long value=0;
463 /* Converts octal string to long, ignoring any non-digit */
465 while (--ndgs) {
466 if (isdigit((int)*p))
467 value = (value << 3) | (long) (*p - '0');
469 p++;
472 return value;
475 /****************************************************************************
476 Compare two strings in a slash insensitive way, allowing s1 to match s2
477 if s1 is an "initial" string (up to directory marker). Thus, if s2 is
478 a file in any subdirectory of s1, declare a match.
479 ***************************************************************************/
481 static int strslashcmp(char *s1, char *s2)
483 char *s1_0=s1;
485 while(*s1 && *s2 && (*s1 == *s2 || tolower_m(*s1) == tolower_m(*s2) ||
486 (*s1 == '\\' && *s2=='/') || (*s1 == '/' && *s2=='\\'))) {
487 s1++; s2++;
490 /* if s1 has a trailing slash, it compared equal, so s1 is an "initial"
491 string of s2.
493 if (!*s1 && s1 != s1_0 && (*(s1-1) == '/' || *(s1-1) == '\\'))
494 return 0;
496 /* ignore trailing slash on s1 */
497 if (!*s2 && (*s1 == '/' || *s1 == '\\') && !*(s1+1))
498 return 0;
500 /* check for s1 is an "initial" string of s2 */
501 if ((*s2 == '/' || *s2 == '\\') && !*s1)
502 return 0;
504 return *s1-*s2;
507 /****************************************************************************
508 Ensure a remote path exists (make if necessary)
509 ***************************************************************************/
511 static bool ensurepath(const char *fname)
513 /* *must* be called with buffer ready malloc'ed */
514 /* ensures path exists */
516 char *partpath, *ffname;
517 size_t fnamelen = strlen(fname)+1;
518 const char *p=fname;
519 char *basehack;
520 char *saveptr;
521 NTSTATUS status;
523 DEBUG(5, ( "Ensurepath called with: %s\n", fname));
525 partpath = SMB_MALLOC(fnamelen);
526 ffname = SMB_MALLOC(fnamelen);
528 if ((partpath == NULL) || (ffname == NULL)){
529 DEBUG(0, ("Out of memory in ensurepath: %s\n", fname));
530 SAFE_FREE(partpath);
531 SAFE_FREE(ffname);
532 return(False);
535 *partpath = 0;
537 /* fname copied to ffname so can strtok_r */
539 strlcpy(ffname, fname, fnamelen);
541 /* do a `basename' on ffname, so don't try and make file name directory */
542 if ((basehack=strrchr_m(ffname, '\\')) == NULL) {
543 SAFE_FREE(partpath);
544 SAFE_FREE(ffname);
545 return True;
546 } else {
547 *basehack='\0';
550 p=strtok_r(ffname, "\\", &saveptr);
552 while (p) {
553 strlcat(partpath, p, fnamelen);
555 status = cli_chkpath(cli, partpath);
556 if (!NT_STATUS_IS_OK(status)) {
557 status = cli_mkdir(cli, partpath);
558 if (!NT_STATUS_IS_OK(status)) {
559 SAFE_FREE(partpath);
560 SAFE_FREE(ffname);
561 DEBUG(0, ("Error mkdir %s\n", nt_errstr(status)));
562 return False;
563 } else {
564 DEBUG(3, ("mkdirhiering %s\n", partpath));
568 strlcat(partpath, "\\", fnamelen);
569 p = strtok_r(NULL, "/\\", &saveptr);
572 SAFE_FREE(partpath);
573 SAFE_FREE(ffname);
574 return True;
577 static int padit(char *buf, uint64_t bufsize, uint64_t padsize)
579 int berr= 0;
580 int bytestowrite;
582 DEBUG(5, ("Padding with %0.f zeros\n", (double)padsize));
583 memset(buf, 0, (size_t)bufsize);
584 while( !berr && padsize > 0 ) {
585 bytestowrite= (int)MIN(bufsize, padsize);
586 berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite;
587 padsize -= bytestowrite;
590 return berr;
593 static void do_setrattr(char *name, uint16 attr, int set)
595 uint16 oldattr;
596 NTSTATUS status;
598 if (!NT_STATUS_IS_OK(cli_getatr(cli, name, &oldattr, NULL, NULL))) {
599 return;
602 if (set == ATTRSET) {
603 attr |= oldattr;
604 } else {
605 attr = oldattr & ~attr;
608 status = cli_setatr(cli, name, attr, 0);
609 if (!NT_STATUS_IS_OK(status)) {
610 DEBUG(1, ("setatr failed: %s\n", nt_errstr(status)));
614 /****************************************************************************
615 append one remote file to the tar file
616 ***************************************************************************/
618 static NTSTATUS do_atar(const char *rname_in, char *lname,
619 struct file_info *finfo1)
621 uint16_t fnum = (uint16_t)-1;
622 uint64_t nread=0;
623 char ftype;
624 file_info2 finfo;
625 bool shallitime=True;
626 char *data = NULL;
627 int read_size = 65520;
628 size_t datalen=0;
629 char *rname = NULL;
630 TALLOC_CTX *ctx = talloc_stackframe();
631 NTSTATUS status = NT_STATUS_OK;
632 struct timespec tp_start;
634 clock_gettime_mono(&tp_start);
636 data = SMB_MALLOC_ARRAY(char, read_size);
637 if (!data) {
638 DEBUG(0,("do_atar: out of memory.\n"));
639 status = NT_STATUS_NO_MEMORY;
640 goto cleanup;
643 ftype = '0'; /* An ordinary file ... */
645 ZERO_STRUCT(finfo);
647 finfo.size = finfo1 -> size;
648 finfo.mode = finfo1 -> mode;
649 finfo.uid = finfo1 -> uid;
650 finfo.gid = finfo1 -> gid;
651 finfo.mtime_ts = finfo1 -> mtime_ts;
652 finfo.atime_ts = finfo1 -> atime_ts;
653 finfo.ctime_ts = finfo1 -> ctime_ts;
655 if (dry_run) {
656 DEBUG(3,("skipping file %s of size %12.0f bytes\n", finfo1->name,
657 (double)finfo.size));
658 shallitime=0;
659 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
660 ntarf++;
661 goto cleanup;
664 rname = clean_name(ctx, rname_in);
665 if (!rname) {
666 status = NT_STATUS_NO_MEMORY;
667 goto cleanup;
670 status = cli_open(cli, rname, O_RDONLY, DENY_NONE, &fnum);
671 if (!NT_STATUS_IS_OK(status)) {
672 DEBUG(0,("%s opening remote file %s (%s)\n",
673 nt_errstr(status),rname, client_get_cur_dir()));
674 goto cleanup;
677 finfo.name = smb_xstrdup(rname);
678 if (finfo.name == NULL) {
679 DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n"));
680 status = NT_STATUS_NO_MEMORY;
681 goto cleanup;
684 DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
686 if (tar_inc && !(finfo.mode & FILE_ATTRIBUTE_ARCHIVE)) {
687 DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
688 shallitime=0;
689 } else if (!tar_system && (finfo.mode & FILE_ATTRIBUTE_SYSTEM)) {
690 DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
691 shallitime=0;
692 } else if (!tar_hidden && (finfo.mode & FILE_ATTRIBUTE_HIDDEN)) {
693 DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
694 shallitime=0;
695 } else {
696 bool wrote_tar_header = False;
698 DEBUG(3,("getting file %s of size %.0f bytes as a tar file %s",
699 finfo.name, (double)finfo.size, lname));
701 do {
703 DEBUG(3,("nread=%.0f\n",(double)nread));
705 status = cli_read(cli, fnum, data, nread,
706 read_size, &datalen);
707 if (!NT_STATUS_IS_OK(status)) {
708 DEBUG(0,("Error reading file %s : %s\n",
709 rname, nt_errstr(status)));
710 break;
713 nread += datalen;
715 /* Only if the first read succeeds, write out the tar header. */
716 if (!wrote_tar_header) {
717 /* write a tar header, don't bother with mode - just set to 100644 */
718 writetarheader(tarhandle, rname, finfo.size,
719 finfo.mtime_ts.tv_sec, "100644 \0", ftype);
720 wrote_tar_header = True;
723 /* if file size has increased since we made file size query, truncate
724 read so tar header for this file will be correct.
727 if (nread > finfo.size) {
728 datalen -= nread - finfo.size;
729 DEBUG(0,("File size change - truncating %s to %.0f bytes\n",
730 finfo.name, (double)finfo.size));
733 /* add received bits of file to buffer - dotarbuf will
734 * write out in 512 byte intervals */
736 if (dotarbuf(tarhandle,data,datalen) != datalen) {
737 DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
738 status = map_nt_error_from_unix(errno);
739 break;
742 if ( (datalen == 0) && (finfo.size != 0) ) {
743 status = NT_STATUS_UNSUCCESSFUL;
744 DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
745 break;
748 datalen=0;
749 } while ( nread < finfo.size );
751 if (wrote_tar_header) {
752 /* pad tar file with zero's if we couldn't get entire file */
753 if (nread < finfo.size) {
754 DEBUG(0, ("Didn't get entire file. size=%.0f, nread=%d\n",
755 (double)finfo.size, (int)nread));
756 if (padit(data, (uint64_t)sizeof(data), finfo.size - nread)) {
757 status = map_nt_error_from_unix(errno);
758 DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
762 /* round tar file to nearest block */
763 if (finfo.size % TBLOCK)
764 dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
766 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
767 ntarf++;
768 } else {
769 DEBUG(4, ("skipping %s - initial read failed (file was locked ?)\n", finfo.name));
770 shallitime=0;
771 status = NT_STATUS_UNSUCCESSFUL;
775 cli_close(cli, fnum);
776 fnum = -1;
778 if (shallitime) {
779 struct timespec tp_end;
780 int this_time;
782 /* if shallitime is true then we didn't skip */
783 if (tar_reset && !dry_run)
784 (void) do_setrattr(finfo.name, FILE_ATTRIBUTE_ARCHIVE, ATTRRESET);
786 clock_gettime_mono(&tp_end);
787 this_time = (tp_end.tv_sec - tp_start.tv_sec)*1000 + (tp_end.tv_nsec - tp_start.tv_nsec)/1000000;
788 get_total_time_ms += this_time;
789 get_total_size += finfo.size;
791 if (tar_noisy) {
792 DEBUG(0, ("%12.0f (%7.1f kb/s) %s\n",
793 (double)finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
794 finfo.name));
797 /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
798 DEBUG(3,("(%g kb/s) (average %g kb/s)\n",
799 finfo.size / MAX(0.001, (1.024*this_time)),
800 get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
803 cleanup:
805 if (fnum != (uint16_t)-1) {
806 cli_close(cli, fnum);
807 fnum = -1;
809 TALLOC_FREE(ctx);
810 SAFE_FREE(data);
811 return status;
814 /****************************************************************************
815 Append single file to tar file (or not)
816 ***************************************************************************/
818 static NTSTATUS do_tar(struct cli_state *cli_state, struct file_info *finfo,
819 const char *dir)
821 TALLOC_CTX *ctx = talloc_stackframe();
822 NTSTATUS status = NT_STATUS_OK;
824 if (strequal(finfo->name,"..") || strequal(finfo->name,".")) {
825 status = NT_STATUS_OK;
826 goto cleanup;
829 /* Is it on the exclude list ? */
830 if (!tar_excl && clipn) {
831 char *exclaim;
833 DEBUG(5, ("Excl: strlen(cur_dir) = %d\n", (int)strlen(client_get_cur_dir())));
835 exclaim = talloc_asprintf(ctx,
836 "%s\\%s",
837 client_get_cur_dir(),
838 finfo->name);
839 if (!exclaim) {
840 status = NT_STATUS_NO_MEMORY;
841 goto cleanup;
844 DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
846 if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
847 (tar_re_search && mask_match_list(exclaim, cliplist, clipn, True))) {
848 DEBUG(3,("Skipping file %s\n", exclaim));
849 TALLOC_FREE(exclaim);
850 status = NT_STATUS_OK;
851 goto cleanup;
853 TALLOC_FREE(exclaim);
856 if (finfo->mode & FILE_ATTRIBUTE_DIRECTORY) {
857 char *saved_curdir = NULL;
858 char *new_cd = NULL;
859 char *mtar_mask = NULL;
861 saved_curdir = talloc_strdup(ctx, client_get_cur_dir());
862 if (!saved_curdir) {
863 status = NT_STATUS_NO_MEMORY;
864 goto cleanup;
867 DEBUG(5, ("strlen(cur_dir)=%d, \
868 strlen(finfo->name)=%d\nname=%s,cur_dir=%s\n",
869 (int)strlen(saved_curdir),
870 (int)strlen(finfo->name), finfo->name, saved_curdir));
872 new_cd = talloc_asprintf(ctx,
873 "%s%s\\",
874 client_get_cur_dir(),
875 finfo->name);
876 if (!new_cd) {
877 status = NT_STATUS_NO_MEMORY;
878 goto cleanup;
880 client_set_cur_dir(new_cd);
882 DEBUG(5, ("Writing a dir, Name = %s\n", client_get_cur_dir()));
884 /* write a tar directory, don't bother with mode - just
885 * set it to 40755 */
886 writetarheader(tarhandle, client_get_cur_dir(), 0,
887 finfo->mtime_ts.tv_sec, "040755 \0", '5');
888 if (tar_noisy) {
889 DEBUG(0,(" directory %s\n",
890 client_get_cur_dir()));
892 ntarf++; /* Make sure we have a file on there */
893 mtar_mask = talloc_asprintf(ctx,
894 "%s*",
895 client_get_cur_dir());
896 if (!mtar_mask) {
897 status = NT_STATUS_NO_MEMORY;
898 goto cleanup;
900 DEBUG(5, ("Doing list with mtar_mask: %s\n", mtar_mask));
901 do_list(mtar_mask, attribute, do_tar, False, True);
902 client_set_cur_dir(saved_curdir);
903 TALLOC_FREE(saved_curdir);
904 TALLOC_FREE(new_cd);
905 TALLOC_FREE(mtar_mask);
906 } else {
907 char *rname = talloc_asprintf(ctx,
908 "%s%s",
909 client_get_cur_dir(),
910 finfo->name);
911 if (!rname) {
912 status = NT_STATUS_NO_MEMORY;
913 goto cleanup;
915 status = do_atar(rname,finfo->name,finfo);
916 TALLOC_FREE(rname);
919 cleanup:
920 TALLOC_FREE(ctx);
921 return status;
924 /****************************************************************************
925 Convert from UNIX to DOS file names
926 ***************************************************************************/
928 static void unfixtarname(char *tptr, char *fp, int l, bool first)
930 /* remove '.' from start of file name, convert from unix /'s to
931 * dos \'s in path. Kill any absolute path names. But only if first!
934 DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
936 if (first) {
937 if (*fp == '.') {
938 fp++;
939 l--;
941 if (*fp == '\\' || *fp == '/') {
942 fp++;
943 l--;
945 if (l <= 0) {
946 return;
950 strlcpy(tptr, fp, l);
951 string_replace(tptr, '/', '\\');
954 /****************************************************************************
955 Move to the next block in the buffer, which may mean read in another set of
956 blocks. FIXME, we should allow more than one block to be skipped.
957 ****************************************************************************/
959 static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
961 int bufread, total = 0;
963 DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp));
964 *bufferp += TBLOCK;
965 total = TBLOCK;
967 if (*bufferp >= (ltarbuf + bufsiz)) {
969 DEBUG(5, ("Reading more data into ltarbuf ...\n"));
972 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>
973 * Fixes bug where read can return short if coming from
974 * a pipe.
977 bufread = read(tarhandle, ltarbuf, bufsiz);
978 total = bufread;
980 while (total < bufsiz) {
981 if (bufread < 0) { /* An error, return false */
982 return (total > 0 ? -2 : bufread);
984 if (bufread == 0) {
985 if (total <= 0) {
986 return -2;
988 break;
990 bufread = read(tarhandle, &ltarbuf[total], bufsiz - total);
991 total += bufread;
994 DEBUG(5, ("Total bytes read ... %i\n", total));
996 *bufferp = ltarbuf;
999 return(total);
1002 /* Skip a file, even if it includes a long file name? */
1003 static int skip_file(int skipsize)
1005 int dsize = skipsize;
1007 DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
1009 /* FIXME, we should skip more than one block at a time */
1011 while (dsize > 0) {
1012 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1013 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1014 return(False);
1016 dsize -= TBLOCK;
1019 return(True);
1022 /*************************************************************
1023 Get a file from the tar file and store it.
1024 When this is called, tarbuf already contains the first
1025 file block. This is a bit broken & needs fixing.
1026 **************************************************************/
1028 static int get_file(file_info2 finfo)
1030 uint16_t fnum = (uint16_t) -1;
1031 int dsize = 0, bpos = 0;
1032 uint64_t rsize = 0, pos = 0;
1033 NTSTATUS status;
1035 DEBUG(5, ("get_file: file: %s, size %.0f\n", finfo.name, (double)finfo.size));
1037 if (!ensurepath(finfo.name)) {
1038 DEBUG(0, ("abandoning restore\n"));
1039 return False;
1042 status = cli_open(cli, finfo.name, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE, &fnum);
1043 if (!NT_STATUS_IS_OK(status)) {
1044 DEBUG(0, ("abandoning restore\n"));
1045 return False;
1048 /* read the blocks from the tar file and write to the remote file */
1050 rsize = finfo.size; /* This is how much to write */
1052 while (rsize > 0) {
1054 /* We can only write up to the end of the buffer */
1055 dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, 65520); /* Calculate the size to write */
1056 dsize = MIN(dsize, rsize); /* Should be only what is left */
1057 DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos));
1059 status = cli_writeall(cli, fnum, 0,
1060 (uint8_t *)(buffer_p + bpos), pos,
1061 dsize, NULL);
1062 if (!NT_STATUS_IS_OK(status)) {
1063 DEBUG(0, ("Error writing remote file: %s\n",
1064 nt_errstr(status)));
1065 return 0;
1068 rsize -= dsize;
1069 pos += dsize;
1071 /* Now figure out how much to move in the buffer */
1073 /* FIXME, we should skip more than one block at a time */
1075 /* First, skip any initial part of the part written that is left over */
1076 /* from the end of the first TBLOCK */
1078 if ((bpos) && ((bpos + dsize) >= TBLOCK)) {
1079 dsize -= (TBLOCK - bpos); /* Get rid of the end of the first block */
1080 bpos = 0;
1082 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) { /* and skip the block */
1083 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1084 return False;
1089 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>.
1090 * If the file being extracted is an exact multiple of
1091 * TBLOCK bytes then we don't want to extract the next
1092 * block from the tarfile here, as it will be done in
1093 * the caller of get_file().
1096 while (((rsize != 0) && (dsize >= TBLOCK)) ||
1097 ((rsize == 0) && (dsize > TBLOCK))) {
1099 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1100 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1101 return False;
1104 dsize -= TBLOCK;
1106 bpos = dsize;
1109 /* Now close the file ... */
1110 status = cli_close(cli, fnum);
1111 if (!NT_STATUS_IS_OK(status)) {
1112 DEBUG(0, ("Error %s closing remote file\n",
1113 nt_errstr(status)));
1114 return(False);
1117 /* Now we update the creation date ... */
1118 DEBUG(5, ("Updating creation date on %s\n", finfo.name));
1120 if (!NT_STATUS_IS_OK(cli_setatr(cli, finfo.name, finfo.mode, finfo.mtime_ts.tv_sec))) {
1121 if (tar_real_noisy) {
1122 DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
1123 /*return(False); */ /* Ignore, as Win95 does not allow changes */
1127 ntarf++;
1128 DEBUG(0, ("restore tar file %s of size %.0f bytes\n", finfo.name, (double)finfo.size));
1129 return(True);
1132 /* Create a directory. We just ensure that the path exists and return as there
1133 is no file associated with a directory
1135 static int get_dir(file_info2 finfo)
1137 DEBUG(0, ("restore directory %s\n", finfo.name));
1139 if (!ensurepath(finfo.name)) {
1140 DEBUG(0, ("Problems creating directory\n"));
1141 return(False);
1143 ntarf++;
1144 return(True);
1147 /* Get a file with a long file name ... first file has file name, next file
1148 has the data. We only want the long file name, as the loop in do_tarput
1149 will deal with the rest.
1151 static char *get_longfilename(file_info2 finfo)
1153 /* finfo.size here is the length of the filename as written by the "/./@LongLink" name
1154 * header call. */
1155 int namesize = finfo.size + strlen(client_get_cur_dir()) + 2;
1156 char *longname = (char *)SMB_MALLOC(namesize);
1157 int offset = 0, left = finfo.size;
1158 bool first = True;
1160 DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
1161 DEBUG(5, ("Len = %.0f\n", (double)finfo.size));
1163 if (longname == NULL) {
1164 DEBUG(0, ("could not allocate buffer of size %d for longname\n", namesize));
1165 return(NULL);
1168 /* First, add cur_dir to the long file name */
1170 if (strlen(client_get_cur_dir()) > 0) {
1171 strncpy(longname, client_get_cur_dir(), namesize);
1172 offset = strlen(client_get_cur_dir());
1175 /* Loop through the blocks picking up the name */
1177 while (left > 0) {
1178 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1179 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1180 SAFE_FREE(longname);
1181 return(NULL);
1184 unfixtarname(longname + offset, buffer_p,
1185 namesize - offset, first--);
1186 DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
1188 offset += TBLOCK;
1189 left -= TBLOCK;
1192 return(longname);
1195 static void do_tarput(void)
1197 file_info2 finfo;
1198 struct timespec tp_start;
1199 char *longfilename = NULL, linkflag;
1200 int skip = False;
1202 ZERO_STRUCT(finfo);
1204 clock_gettime_mono(&tp_start);
1205 DEBUG(5, ("RJS do_tarput called ...\n"));
1207 buffer_p = tarbuf + tbufsiz; /* init this to force first read */
1209 /* Now read through those files ... */
1210 while (True) {
1211 /* Get us to the next block, or the first block first time around */
1212 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1213 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1214 SAFE_FREE(longfilename);
1215 return;
1218 DEBUG(5, ("Reading the next header ...\n"));
1220 switch (readtarheader((union hblock *) buffer_p,
1221 &finfo, client_get_cur_dir())) {
1222 case -2: /* Hmm, not good, but not fatal */
1223 DEBUG(0, ("Skipping %s...\n", finfo.name));
1224 if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) && !skip_file(finfo.size)) {
1225 DEBUG(0, ("Short file, bailing out...\n"));
1226 SAFE_FREE(longfilename);
1227 return;
1229 break;
1231 case -1:
1232 DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
1233 SAFE_FREE(longfilename);
1234 return;
1236 case 0: /* chksum is zero - looks like an EOF */
1237 DEBUG(0, ("tar: restored %d files and directories\n", ntarf));
1238 SAFE_FREE(longfilename);
1239 return; /* Hmmm, bad here ... */
1241 default:
1242 /* No action */
1243 break;
1246 /* Now, do we have a long file name? */
1247 if (longfilename != NULL) {
1248 SAFE_FREE(finfo.name); /* Free the space already allocated */
1249 finfo.name = longfilename;
1250 longfilename = NULL;
1253 /* Well, now we have a header, process the file ... */
1254 /* Should we skip the file? We have the long name as well here */
1255 skip = clipn && ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl) ||
1256 (tar_re_search && mask_match_list(finfo.name, cliplist, clipn, True)));
1258 DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
1259 if (skip) {
1260 skip_file(finfo.size);
1261 continue;
1264 /* We only get this far if we should process the file */
1265 linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
1266 switch (linkflag) {
1267 case '0': /* Should use symbolic names--FIXME */
1269 * Skip to the next block first, so we can get the file, FIXME, should
1270 * be in get_file ...
1271 * The 'finfo.size != 0' fix is from Bob Boehmer <boehmer@worldnet.att.net>
1272 * Fixes bug where file size in tarfile is zero.
1274 if ((finfo.size != 0) && next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1275 DEBUG(0, ("Short file, bailing out...\n"));
1276 return;
1278 if (!get_file(finfo)) {
1279 DEBUG(0, ("Abandoning restore\n"));
1280 return;
1282 break;
1283 case '5':
1284 if (!get_dir(finfo)) {
1285 DEBUG(0, ("Abandoning restore \n"));
1286 return;
1288 break;
1289 case 'L':
1290 SAFE_FREE(longfilename);
1291 longfilename = get_longfilename(finfo);
1292 if (!longfilename) {
1293 DEBUG(0, ("abandoning restore\n"));
1294 return;
1296 DEBUG(5, ("Long file name: %s\n", longfilename));
1297 break;
1299 default:
1300 skip_file(finfo.size); /* Don't handle these yet */
1301 break;
1307 * samba interactive commands
1310 /****************************************************************************
1311 Blocksize command
1312 ***************************************************************************/
1314 int cmd_block(void)
1316 TALLOC_CTX *ctx = talloc_tos();
1317 char *buf;
1318 int block;
1320 if (!next_token_talloc(ctx, (const char **)&cmd_ptr,&buf,NULL)) {
1321 DEBUG(0, ("blocksize <n>\n"));
1322 return 1;
1325 block=atoi(buf);
1326 if (block < 0 || block > 65535) {
1327 DEBUG(0, ("blocksize out of range"));
1328 return 1;
1331 blocksize=block;
1332 DEBUG(2,("blocksize is now %d\n", blocksize));
1333 return 0;
1336 /****************************************************************************
1337 command to set incremental / reset mode
1338 ***************************************************************************/
1340 int cmd_tarmode(void)
1342 TALLOC_CTX *ctx = talloc_tos();
1343 char *buf;
1345 while (next_token_talloc(ctx, (const char **)&cmd_ptr,&buf,NULL)) {
1346 if (strequal(buf, "full"))
1347 tar_inc=False;
1348 else if (strequal(buf, "inc"))
1349 tar_inc=True;
1350 else if (strequal(buf, "reset"))
1351 tar_reset=True;
1352 else if (strequal(buf, "noreset"))
1353 tar_reset=False;
1354 else if (strequal(buf, "system"))
1355 tar_system=True;
1356 else if (strequal(buf, "nosystem"))
1357 tar_system=False;
1358 else if (strequal(buf, "hidden"))
1359 tar_hidden=True;
1360 else if (strequal(buf, "nohidden"))
1361 tar_hidden=False;
1362 else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
1363 tar_noisy=True;
1364 else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
1365 tar_noisy=False;
1366 else
1367 DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
1368 TALLOC_FREE(buf);
1371 DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
1372 tar_inc ? "incremental" : "full",
1373 tar_system ? "system" : "nosystem",
1374 tar_hidden ? "hidden" : "nohidden",
1375 tar_reset ? "reset" : "noreset",
1376 tar_noisy ? "verbose" : "quiet"));
1377 return 0;
1380 /****************************************************************************
1381 Feeble attrib command
1382 ***************************************************************************/
1384 int cmd_setmode(void)
1386 TALLOC_CTX *ctx = talloc_tos();
1387 char *q;
1388 char *buf;
1389 char *fname = NULL;
1390 uint16 attra[2];
1391 int direct=1;
1393 attra[0] = attra[1] = 0;
1395 if (!next_token_talloc(ctx, (const char **)&cmd_ptr,&buf,NULL)) {
1396 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1397 return 1;
1400 fname = talloc_asprintf(ctx,
1401 "%s%s",
1402 client_get_cur_dir(),
1403 buf);
1404 if (!fname) {
1405 return 1;
1408 while (next_token_talloc(ctx, (const char **)&cmd_ptr,&buf,NULL)) {
1409 q=buf;
1411 while(*q) {
1412 switch (*q++) {
1413 case '+':
1414 direct=1;
1415 break;
1416 case '-':
1417 direct=0;
1418 break;
1419 case 'r':
1420 attra[direct]|=FILE_ATTRIBUTE_READONLY;
1421 break;
1422 case 'h':
1423 attra[direct]|=FILE_ATTRIBUTE_HIDDEN;
1424 break;
1425 case 's':
1426 attra[direct]|=FILE_ATTRIBUTE_SYSTEM;
1427 break;
1428 case 'a':
1429 attra[direct]|=FILE_ATTRIBUTE_ARCHIVE;
1430 break;
1431 default:
1432 DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1433 return 1;
1438 if (attra[ATTRSET]==0 && attra[ATTRRESET]==0) {
1439 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1440 return 1;
1443 DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1444 do_setrattr(fname, attra[ATTRSET], ATTRSET);
1445 do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
1446 return 0;
1450 Convert list of tokens to array; dependent on above routine.
1451 Uses the global cmd_ptr from above - bit of a hack.
1454 static char **toktocliplist(int *ctok, const char *sep)
1456 char *s=(char *)cmd_ptr;
1457 int ictok=0;
1458 char **ret, **iret;
1460 if (!sep)
1461 sep = " \t\n\r";
1463 while(*s && strchr_m(sep,*s))
1464 s++;
1466 /* nothing left? */
1467 if (!*s)
1468 return(NULL);
1470 do {
1471 ictok++;
1472 while(*s && (!strchr_m(sep,*s)))
1473 s++;
1474 while(*s && strchr_m(sep,*s))
1475 *s++=0;
1476 } while(*s);
1478 *ctok=ictok;
1479 s=(char *)cmd_ptr;
1481 if (!(ret=iret=SMB_MALLOC_ARRAY(char *,ictok+1)))
1482 return NULL;
1484 while(ictok--) {
1485 *iret++=s;
1486 if (ictok > 0) {
1487 while(*s++)
1489 while(!*s)
1490 s++;
1494 ret[*ctok] = NULL;
1495 return ret;
1498 /****************************************************************************
1499 Principal command for creating / extracting
1500 ***************************************************************************/
1502 int cmd_tar(void)
1504 TALLOC_CTX *ctx = talloc_tos();
1505 char *buf;
1506 char **argl = NULL;
1507 int argcl = 0;
1508 int ret;
1510 if (!next_token_talloc(ctx, (const char **)&cmd_ptr,&buf,NULL)) {
1511 DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
1512 return 1;
1515 argl=toktocliplist(&argcl, NULL);
1516 if (!tar_parseargs(argcl, argl, buf, 0)) {
1517 SAFE_FREE(argl);
1518 return 1;
1521 ret = process_tar();
1522 SAFE_FREE(argl);
1523 return ret;
1526 /****************************************************************************
1527 Command line (option) version
1528 ***************************************************************************/
1530 int process_tar(void)
1532 TALLOC_CTX *ctx = talloc_tos();
1533 int rc = 0;
1534 initarbuf();
1535 switch(tar_type) {
1536 case 'x':
1538 #if 0
1539 do_tarput2();
1540 #else
1541 do_tarput();
1542 #endif
1543 SAFE_FREE(tarbuf);
1544 close(tarhandle);
1545 break;
1546 case 'r':
1547 case 'c':
1548 if (clipn && tar_excl) {
1549 int i;
1550 char *tarmac = NULL;
1552 for (i=0; i<clipn; i++) {
1553 DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
1555 if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1556 *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1559 if (strrchr_m(cliplist[i], '\\')) {
1560 char *p;
1561 char saved_char;
1562 char *saved_dir = talloc_strdup(ctx,
1563 client_get_cur_dir());
1564 if (!saved_dir) {
1565 return 1;
1568 if (*cliplist[i]=='\\') {
1569 tarmac = talloc_strdup(ctx,
1570 cliplist[i]);
1571 } else {
1572 tarmac = talloc_asprintf(ctx,
1573 "%s%s",
1574 client_get_cur_dir(),
1575 cliplist[i]);
1577 if (!tarmac) {
1578 return 1;
1581 * Strip off the last \\xxx
1582 * xxx element of tarmac to set
1583 * it as current directory.
1585 p = strrchr_m(tarmac, '\\');
1586 if (!p) {
1587 return 1;
1589 saved_char = p[1];
1590 p[1] = '\0';
1592 client_set_cur_dir(tarmac);
1595 * Restore the character we
1596 * just replaced to
1597 * put the pathname
1598 * back as it was.
1600 p[1] = saved_char;
1602 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1603 do_list(tarmac,attribute,do_tar, False, True);
1605 client_set_cur_dir(saved_dir);
1607 TALLOC_FREE(saved_dir);
1608 TALLOC_FREE(tarmac);
1609 } else {
1610 tarmac = talloc_asprintf(ctx,
1611 "%s%s",
1612 client_get_cur_dir(),
1613 cliplist[i]);
1614 if (!tarmac) {
1615 return 1;
1617 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1618 do_list(tarmac,attribute,do_tar, False, True);
1619 TALLOC_FREE(tarmac);
1622 } else {
1623 char *mask = talloc_asprintf(ctx,
1624 "%s\\*",
1625 client_get_cur_dir());
1626 if (!mask) {
1627 return 1;
1629 DEBUG(5, ("process_tar, do_list with mask: %s\n", mask));
1630 do_list(mask,attribute,do_tar,False, True);
1631 TALLOC_FREE(mask);
1634 if (ntarf) {
1635 dotareof(tarhandle);
1637 close(tarhandle);
1638 SAFE_FREE(tarbuf);
1640 DEBUG(0, ("tar: dumped %d files and directories\n", ntarf));
1641 DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf));
1642 break;
1645 if (must_free_cliplist) {
1646 int i;
1647 for (i = 0; i < clipn; ++i) {
1648 SAFE_FREE(cliplist[i]);
1650 SAFE_FREE(cliplist);
1651 cliplist = NULL;
1652 clipn = 0;
1653 must_free_cliplist = False;
1655 return rc;
1658 /****************************************************************************
1659 Find a token (filename) in a clip list
1660 ***************************************************************************/
1662 static int clipfind(char **aret, int ret, char *tok)
1664 if (aret==NULL)
1665 return 0;
1667 /* ignore leading slashes or dots in token */
1668 while(strchr_m("/\\.", *tok))
1669 tok++;
1671 while(ret--) {
1672 char *pkey=*aret++;
1674 /* ignore leading slashes or dots in list */
1675 while(strchr_m("/\\.", *pkey))
1676 pkey++;
1678 if (!strslashcmp(pkey, tok))
1679 return 1;
1681 return 0;
1684 /****************************************************************************
1685 Read list of files to include from the file and initialize cliplist
1686 accordingly.
1687 ***************************************************************************/
1689 static int read_inclusion_file(char *filename)
1691 XFILE *inclusion = NULL;
1692 char buf[PATH_MAX + 1];
1693 char *inclusion_buffer = NULL;
1694 int inclusion_buffer_size = 0;
1695 int inclusion_buffer_sofar = 0;
1696 char *p;
1697 char *tmpstr;
1698 int i;
1699 int error = 0;
1701 clipn = 0;
1702 buf[PATH_MAX] = '\0'; /* guarantee null-termination */
1703 if ((inclusion = x_fopen(filename, O_RDONLY, 0)) == NULL) {
1704 /* XXX It would be better to include a reason for failure, but without
1705 * autoconf, it's hard to use strerror, sys_errlist, etc.
1707 DEBUG(0,("Unable to open inclusion file %s\n", filename));
1708 return 0;
1711 while ((! error) && (x_fgets(buf, sizeof(buf)-1, inclusion))) {
1712 if (inclusion_buffer == NULL) {
1713 inclusion_buffer_size = 1024;
1714 if ((inclusion_buffer = (char *)SMB_MALLOC(inclusion_buffer_size)) == NULL) {
1715 DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1716 error = 1;
1717 break;
1721 if (buf[strlen(buf)-1] == '\n') {
1722 buf[strlen(buf)-1] = '\0';
1725 if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1726 inclusion_buffer_size *= 2;
1727 inclusion_buffer = (char *)SMB_REALLOC(inclusion_buffer,inclusion_buffer_size);
1728 if (!inclusion_buffer) {
1729 DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1730 inclusion_buffer_size));
1731 error = 1;
1732 break;
1736 strlcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
1737 inclusion_buffer_sofar += strlen(buf) + 1;
1738 clipn++;
1740 x_fclose(inclusion);
1742 if (! error) {
1743 /* Allocate an array of clipn + 1 char*'s for cliplist */
1744 cliplist = SMB_MALLOC_ARRAY(char *, clipn + 1);
1745 if (cliplist == NULL) {
1746 DEBUG(0,("failure allocating memory for cliplist\n"));
1747 error = 1;
1748 } else {
1749 cliplist[clipn] = NULL;
1750 p = inclusion_buffer;
1751 for (i = 0; (! error) && (i < clipn); i++) {
1752 /* set current item to NULL so array will be null-terminated even if
1753 * malloc fails below. */
1754 cliplist[i] = NULL;
1755 if ((tmpstr = (char *)SMB_MALLOC(strlen(p)+1)) == NULL) {
1756 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
1757 error = 1;
1758 } else {
1759 unfixtarname(tmpstr, p, strlen(p) + 1, True);
1760 cliplist[i] = tmpstr;
1761 if ((p = strchr_m(p, '\000')) == NULL) {
1762 DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1763 abort();
1766 ++p;
1768 must_free_cliplist = True;
1772 SAFE_FREE(inclusion_buffer);
1773 if (error) {
1774 if (cliplist) {
1775 char **pp;
1776 /* We know cliplist is always null-terminated */
1777 for (pp = cliplist; *pp; ++pp) {
1778 SAFE_FREE(*pp);
1780 SAFE_FREE(cliplist);
1781 cliplist = NULL;
1782 must_free_cliplist = False;
1784 return 0;
1787 /* cliplist and its elements are freed at the end of process_tar. */
1788 return 1;
1791 /****************************************************************************
1792 Parse tar arguments. Sets tar_type, tar_excl, etc.
1793 ***************************************************************************/
1795 int tar_parseargs(int argc, char *argv[], const char *Optarg, int Optind)
1797 int newOptind = Optind;
1798 char tar_clipfl='\0';
1800 /* Reset back to defaults - could be from interactive version
1801 * reset mode and archive mode left as they are though
1803 tar_type='\0';
1804 tar_excl=True;
1805 dry_run=False;
1807 while (*Optarg) {
1808 switch(*Optarg++) {
1809 case 'c':
1810 tar_type='c';
1811 break;
1812 case 'x':
1813 if (tar_type=='c') {
1814 printf("Tar must be followed by only one of c or x.\n");
1815 return 0;
1817 tar_type='x';
1818 break;
1819 case 'b':
1820 if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1821 DEBUG(0,("Option b must be followed by valid blocksize\n"));
1822 return 0;
1823 } else {
1824 Optind++;
1825 newOptind++;
1827 break;
1828 case 'g':
1829 tar_inc=True;
1830 break;
1831 case 'N':
1832 if (Optind>=argc) {
1833 DEBUG(0,("Option N must be followed by valid file name\n"));
1834 return 0;
1835 } else {
1836 SMB_STRUCT_STAT stbuf;
1838 if (sys_stat(argv[Optind], &stbuf,
1839 false) == 0) {
1840 newer_than = convert_timespec_to_time_t(
1841 stbuf.st_ex_mtime);
1842 DEBUG(1,("Getting files newer than %s",
1843 time_to_asc(newer_than)));
1844 newOptind++;
1845 Optind++;
1846 } else {
1847 DEBUG(0,("Error setting newer-than time\n"));
1848 return 0;
1851 break;
1852 case 'a':
1853 tar_reset=True;
1854 break;
1855 case 'q':
1856 tar_noisy=False;
1857 break;
1858 case 'I':
1859 if (tar_clipfl) {
1860 DEBUG(0,("Only one of I,X,F must be specified\n"));
1861 return 0;
1863 tar_clipfl='I';
1864 break;
1865 case 'X':
1866 if (tar_clipfl) {
1867 DEBUG(0,("Only one of I,X,F must be specified\n"));
1868 return 0;
1870 tar_clipfl='X';
1871 break;
1872 case 'F':
1873 if (tar_clipfl) {
1874 DEBUG(0,("Only one of I,X,F must be specified\n"));
1875 return 0;
1877 tar_clipfl='F';
1878 break;
1879 case 'r':
1880 DEBUG(0, ("tar_re_search set\n"));
1881 tar_re_search = True;
1882 break;
1883 case 'n':
1884 if (tar_type == 'c') {
1885 DEBUG(0, ("dry_run set\n"));
1886 dry_run = True;
1887 } else {
1888 DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1889 return 0;
1891 break;
1892 default:
1893 DEBUG(0,("Unknown tar option\n"));
1894 return 0;
1898 if (!tar_type) {
1899 printf("Option T must be followed by one of c or x.\n");
1900 return 0;
1903 /* tar_excl is true if cliplist lists files to be included.
1904 * Both 'I' and 'F' mean include. */
1905 tar_excl=tar_clipfl!='X';
1907 if (tar_clipfl=='F') {
1908 if (argc-Optind-1 != 1) {
1909 DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1910 return 0;
1912 newOptind++;
1913 /* Optind points at the tar output file, Optind+1 at the inclusion file. */
1914 if (! read_inclusion_file(argv[Optind+1])) {
1915 return 0;
1917 } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
1918 char *tmpstr;
1919 char **tmplist;
1920 int clipcount;
1922 cliplist=argv+Optind+1;
1923 clipn=argc-Optind-1;
1924 clipcount = clipn;
1926 if ((tmplist=SMB_MALLOC_ARRAY(char *,clipn)) == NULL) {
1927 DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n", clipn));
1928 return 0;
1931 for (clipcount = 0; clipcount < clipn; clipcount++) {
1933 DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1935 if ((tmpstr = (char *)SMB_MALLOC(strlen(cliplist[clipcount])+1)) == NULL) {
1936 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", clipcount));
1937 SAFE_FREE(tmplist);
1938 return 0;
1941 unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
1942 tmplist[clipcount] = tmpstr;
1943 DEBUG(5, ("Processed an item, %s\n", tmpstr));
1945 DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1948 cliplist = tmplist;
1949 must_free_cliplist = True;
1951 newOptind += clipn;
1954 if (Optind+1<argc && tar_re_search && tar_clipfl != 'F') {
1955 /* Doing regular expression seaches not from an inclusion file. */
1956 clipn=argc-Optind-1;
1957 cliplist=argv+Optind+1;
1958 newOptind += clipn;
1961 if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1962 /* Sets tar handle to either 0 or 1, as appropriate */
1963 tarhandle=(tar_type=='c');
1965 * Make sure that dbf points to stderr if we are using stdout for
1966 * tar output
1968 if (tarhandle == 1) {
1969 setup_logging("smbclient", DEBUG_STDERR);
1971 if (!argv[Optind]) {
1972 DEBUG(0,("Must specify tar filename\n"));
1973 return 0;
1975 if (!strcmp(argv[Optind], "-")) {
1976 newOptind++;
1979 } else {
1980 if (tar_type=='c' && dry_run) {
1981 tarhandle=-1;
1982 } else if ((tar_type=='x' && (tarhandle = open(argv[Optind], O_RDONLY, 0)) == -1)
1983 || (tar_type=='c' && (tarhandle=creat(argv[Optind], 0644)) < 0)) {
1984 DEBUG(0,("Error opening local file %s - %s\n", argv[Optind], strerror(errno)));
1985 return(0);
1987 newOptind++;
1990 return newOptind;