s3-client/clitar.c: Fix cli_errstr() usage (part of bug #7864)
[Samba/gebeck_regimport.git] / source3 / client / clitar.c
blob4dc202e17ea39e5b47559c59c192cc09f454f659
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 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 ... */
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 uint16 cnum;
109 extern bool readbraw_supported;
110 extern int max_xmit;
111 extern int get_total_time_ms;
112 extern int get_total_size;
114 static int blocksize=20;
115 static int tarhandle;
117 static void writetarheader(int f, const char *aname, uint64_t size, time_t mtime,
118 const char *amode, unsigned char ftype);
119 static NTSTATUS do_atar(const char *rname_in, char *lname,
120 struct file_info *finfo1);
121 static NTSTATUS do_tar(struct cli_state *cli_state, struct file_info *finfo,
122 const char *dir);
123 static void oct_it(uint64_t value, int ndgs, char *p);
124 static void fixtarname(char *tptr, const char *fp, size_t l);
125 static int dotarbuf(int f, char *b, int n);
126 static void dozerobuf(int f, int n);
127 static void dotareof(int f);
128 static void initarbuf(void);
130 /* restore functions */
131 static long readtarheader(union hblock *hb, file_info2 *finfo, const char *prefix);
132 static long unoct(char *p, int ndgs);
133 static void do_tarput(void);
134 static void unfixtarname(char *tptr, char *fp, int l, bool first);
137 * tar specific utitlities
140 /****************************************************************************
141 Write a tar header to buffer
142 ****************************************************************************/
144 static void writetarheader(int f, const char *aname, uint64_t size, time_t mtime,
145 const char *amode, unsigned char ftype)
147 union hblock hb;
148 int i, chk, l;
149 char *jp;
151 DEBUG(5, ("WriteTarHdr, Type = %c, Size= %.0f, Name = %s\n", ftype, (double)size, aname));
153 memset(hb.dummy, 0, sizeof(hb.dummy));
155 l=strlen(aname);
156 /* We will be prepending a '.' in fixtarheader so use +2 to
157 * take care of the . and terminating zero. JRA.
159 if (l+2 >= NAMSIZ) {
160 /* write a GNU tar style long header */
161 char *b;
162 b = (char *)SMB_MALLOC(l+TBLOCK+100);
163 if (!b) {
164 DEBUG(0,("out of memory\n"));
165 exit(1);
167 writetarheader(f, "/./@LongLink", l+2, 0, " 0 \0", 'L');
168 memset(b, 0, l+TBLOCK+100);
169 fixtarname(b, aname, l+2);
170 i = strlen(b)+1;
171 DEBUG(5, ("File name in tar file: %s, size=%d, \n", b, (int)strlen(b)));
172 dotarbuf(f, b, TBLOCK*(((i-1)/TBLOCK)+1));
173 SAFE_FREE(b);
176 fixtarname(hb.dbuf.name, aname, (l+2 >= NAMSIZ) ? NAMSIZ : l + 2);
178 if (lowercase)
179 strlower_m(hb.dbuf.name);
181 /* write out a "standard" tar format header */
183 hb.dbuf.name[NAMSIZ-1]='\0';
184 strlcpy(hb.dbuf.mode, amode ? amode : "", sizeof(hb.dbuf.mode));
185 oct_it((uint64_t)0, 8, hb.dbuf.uid);
186 oct_it((uint64_t)0, 8, hb.dbuf.gid);
187 oct_it((uint64_t) size, 13, hb.dbuf.size);
188 if (size > (uint64_t)077777777777LL) {
189 /* This is a non-POSIX compatible extention to store files
190 greater than 8GB. */
192 memset(hb.dbuf.size, 0, 4);
193 hb.dbuf.size[0]=128;
194 for (i = 8, jp=(char*)&size; i; i--)
195 hb.dbuf.size[i+3] = *(jp++);
197 oct_it((uint64_t) mtime, 13, hb.dbuf.mtime);
198 memcpy(hb.dbuf.chksum, " ", sizeof(hb.dbuf.chksum));
199 memset(hb.dbuf.linkname, 0, NAMSIZ);
200 hb.dbuf.linkflag=ftype;
202 for (chk=0, i=sizeof(hb.dummy), jp=hb.dummy; --i>=0;)
203 chk+=(0xFF & *jp++);
205 oct_it((uint64_t) chk, 8, hb.dbuf.chksum);
206 hb.dbuf.chksum[6] = '\0';
208 (void) dotarbuf(f, hb.dummy, sizeof(hb.dummy));
211 /****************************************************************************
212 Read a tar header into a hblock structure, and validate
213 ***************************************************************************/
215 static long readtarheader(union hblock *hb, file_info2 *finfo, const char *prefix)
217 long chk, fchk;
218 int i;
219 char *jp;
222 * read in a "standard" tar format header - we're not that interested
223 * in that many fields, though
226 /* check the checksum */
227 for (chk=0, i=sizeof(hb->dummy), jp=hb->dummy; --i>=0;)
228 chk+=(0xFF & *jp++);
230 if (chk == 0)
231 return chk;
233 /* compensate for blanks in chksum header */
234 for (i=sizeof(hb->dbuf.chksum), jp=hb->dbuf.chksum; --i>=0;)
235 chk-=(0xFF & *jp++);
237 chk += ' ' * sizeof(hb->dbuf.chksum);
239 fchk=unoct(hb->dbuf.chksum, sizeof(hb->dbuf.chksum));
241 DEBUG(5, ("checksum totals chk=%ld fchk=%ld chksum=%s\n",
242 chk, fchk, hb->dbuf.chksum));
244 if (fchk != chk) {
245 DEBUG(0, ("checksums don't match %ld %ld\n", fchk, chk));
246 dump_data(5, (uint8 *)hb - TBLOCK, TBLOCK *3);
247 return -1;
250 if ((finfo->name = SMB_MALLOC(strlen(prefix) + strlen(hb -> dbuf.name) + 4)) == NULL) {
251 DEBUG(0, ("Out of space creating file_info2 for %s\n", hb -> dbuf.name));
252 return(-1);
255 strlcpy(finfo->name, prefix, strlen(prefix) + strlen(hb -> dbuf.name) + 4);
257 /* use l + 1 to do the null too; do prefix - prefcnt to zap leading slash */
258 unfixtarname(finfo->name + strlen(prefix), hb->dbuf.name,
259 strlen(hb->dbuf.name) + 1, True);
261 /* can't handle some links at present */
262 if ((hb->dbuf.linkflag != '0') && (hb -> dbuf.linkflag != '5')) {
263 if (hb->dbuf.linkflag == 0) {
264 DEBUG(6, ("Warning: NULL link flag (gnu tar archive ?) %s\n",
265 finfo->name));
266 } else {
267 if (hb -> dbuf.linkflag == 'L') { /* We have a longlink */
268 /* Do nothing here at the moment. do_tarput will handle this
269 as long as the longlink gets back to it, as it has to advance
270 the buffer pointer, etc */
271 } else {
272 DEBUG(0, ("this tar file appears to contain some kind \
273 of link other than a GNUtar Longlink - ignoring\n"));
274 return -2;
279 if ((unoct(hb->dbuf.mode, sizeof(hb->dbuf.mode)) & S_IFDIR) ||
280 (*(finfo->name+strlen(finfo->name)-1) == '\\')) {
281 finfo->mode=FILE_ATTRIBUTE_DIRECTORY;
282 } else {
283 finfo->mode=0; /* we don't care about mode at the moment, we'll
284 * just make it a regular file */
288 * Bug fix by richard@sj.co.uk
290 * REC: restore times correctly (as does tar)
291 * We only get the modification time of the file; set the creation time
292 * from the mod. time, and the access time to current time
294 finfo->mtime_ts = finfo->ctime_ts =
295 convert_time_t_to_timespec((time_t)strtol(hb->dbuf.mtime, NULL, 8));
296 finfo->atime_ts = convert_time_t_to_timespec(time(NULL));
297 finfo->size = unoct(hb->dbuf.size, sizeof(hb->dbuf.size));
299 return True;
302 /****************************************************************************
303 Write out the tar buffer to tape or wherever
304 ****************************************************************************/
306 static int dotarbuf(int f, char *b, int n)
308 int fail=1, writ=n;
310 if (dry_run) {
311 return writ;
313 /* This routine and the next one should be the only ones that do write()s */
314 if (tp + n >= tbufsiz) {
315 int diff;
317 diff=tbufsiz-tp;
318 memcpy(tarbuf + tp, b, diff);
319 fail=fail && (1+sys_write(f, tarbuf, tbufsiz));
320 n-=diff;
321 b+=diff;
322 tp=0;
324 while (n >= tbufsiz) {
325 fail=fail && (1 + sys_write(f, b, tbufsiz));
326 n-=tbufsiz;
327 b+=tbufsiz;
331 if (n>0) {
332 memcpy(tarbuf+tp, b, n);
333 tp+=n;
336 return(fail ? writ : 0);
339 /****************************************************************************
340 Write zeros to buffer / tape
341 ****************************************************************************/
343 static void dozerobuf(int f, int n)
345 /* short routine just to write out n zeros to buffer -
346 * used to round files to nearest block
347 * and to do tar EOFs */
349 if (dry_run)
350 return;
352 if (n+tp >= tbufsiz) {
353 memset(tarbuf+tp, 0, tbufsiz-tp);
354 if (sys_write(f, tarbuf, tbufsiz) != tbufsiz) {
355 DEBUG(0, ("dozerobuf: sys_write fail\n"));
356 return;
358 memset(tarbuf, 0, (tp+=n-tbufsiz));
359 } else {
360 memset(tarbuf+tp, 0, n);
361 tp+=n;
365 /****************************************************************************
366 Malloc tape buffer
367 ****************************************************************************/
369 static void initarbuf(void)
371 /* initialize tar buffer */
372 tbufsiz=blocksize*TBLOCK;
373 tarbuf=(char *)SMB_MALLOC(tbufsiz); /* FIXME: We might not get the buffer */
375 /* reset tar buffer pointer and tar file counter and total dumped */
376 tp=0; ntarf=0; ttarf=0;
379 /****************************************************************************
380 Write two zero blocks at end of file
381 ****************************************************************************/
383 static void dotareof(int f)
385 SMB_STRUCT_STAT stbuf;
386 /* Two zero blocks at end of file, write out full buffer */
388 if (dry_run)
389 return;
391 (void) dozerobuf(f, TBLOCK);
392 (void) dozerobuf(f, TBLOCK);
394 if (sys_fstat(f, &stbuf, false) == -1) {
395 DEBUG(0, ("Couldn't stat file handle\n"));
396 return;
399 /* Could be a pipe, in which case S_ISREG should fail,
400 * and we should write out at full size */
401 if (tp > 0) {
402 size_t towrite = S_ISREG(stbuf.st_ex_mode) ? tp : tbufsiz;
403 if (sys_write(f, tarbuf, towrite) != towrite) {
404 DEBUG(0,("dotareof: sys_write fail\n"));
409 /****************************************************************************
410 (Un)mangle DOS pathname, make nonabsolute
411 ****************************************************************************/
413 static void fixtarname(char *tptr, const char *fp, size_t l)
415 /* add a '.' to start of file name, convert from ugly dos \'s in path
416 * to lovely unix /'s :-} */
417 *tptr++='.';
418 l--;
420 StrnCpy(tptr, fp, l-1);
421 string_replace(tptr, '\\', '/');
424 /****************************************************************************
425 Convert from decimal to octal string
426 ****************************************************************************/
428 static void oct_it (uint64_t value, int ndgs, char *p)
430 /* Converts long to octal string, pads with leading zeros */
432 /* skip final null, but do final space */
433 --ndgs;
434 p[--ndgs] = ' ';
436 /* Loop does at least one digit */
437 do {
438 p[--ndgs] = '0' + (char) (value & 7);
439 value >>= 3;
440 } while (ndgs > 0 && value != 0);
442 /* Do leading zeros */
443 while (ndgs > 0)
444 p[--ndgs] = '0';
447 /****************************************************************************
448 Convert from octal string to long
449 ***************************************************************************/
451 static long unoct(char *p, int ndgs)
453 long value=0;
454 /* Converts octal string to long, ignoring any non-digit */
456 while (--ndgs) {
457 if (isdigit((int)*p))
458 value = (value << 3) | (long) (*p - '0');
460 p++;
463 return value;
466 /****************************************************************************
467 Compare two strings in a slash insensitive way, allowing s1 to match s2
468 if s1 is an "initial" string (up to directory marker). Thus, if s2 is
469 a file in any subdirectory of s1, declare a match.
470 ***************************************************************************/
472 static int strslashcmp(char *s1, char *s2)
474 char *s1_0=s1;
476 while(*s1 && *s2 && (*s1 == *s2 || tolower_ascii(*s1) == tolower_ascii(*s2) ||
477 (*s1 == '\\' && *s2=='/') || (*s1 == '/' && *s2=='\\'))) {
478 s1++; s2++;
481 /* if s1 has a trailing slash, it compared equal, so s1 is an "initial"
482 string of s2.
484 if (!*s1 && s1 != s1_0 && (*(s1-1) == '/' || *(s1-1) == '\\'))
485 return 0;
487 /* ignore trailing slash on s1 */
488 if (!*s2 && (*s1 == '/' || *s1 == '\\') && !*(s1+1))
489 return 0;
491 /* check for s1 is an "initial" string of s2 */
492 if ((*s2 == '/' || *s2 == '\\') && !*s1)
493 return 0;
495 return *s1-*s2;
498 /****************************************************************************
499 Ensure a remote path exists (make if necessary)
500 ***************************************************************************/
502 static bool ensurepath(const char *fname)
504 /* *must* be called with buffer ready malloc'ed */
505 /* ensures path exists */
507 char *partpath, *ffname;
508 size_t fnamelen = strlen(fname)+1;
509 const char *p=fname;
510 char *basehack;
511 char *saveptr;
512 NTSTATUS status;
514 DEBUG(5, ( "Ensurepath called with: %s\n", fname));
516 partpath = SMB_MALLOC(fnamelen);
517 ffname = SMB_MALLOC(fnamelen);
519 if ((partpath == NULL) || (ffname == NULL)){
520 DEBUG(0, ("Out of memory in ensurepath: %s\n", fname));
521 SAFE_FREE(partpath);
522 SAFE_FREE(ffname);
523 return(False);
526 *partpath = 0;
528 /* fname copied to ffname so can strtok_r */
530 strlcpy(ffname, fname, fnamelen);
532 /* do a `basename' on ffname, so don't try and make file name directory */
533 if ((basehack=strrchr_m(ffname, '\\')) == NULL) {
534 SAFE_FREE(partpath);
535 SAFE_FREE(ffname);
536 return True;
537 } else {
538 *basehack='\0';
541 p=strtok_r(ffname, "\\", &saveptr);
543 while (p) {
544 strlcat(partpath, p, fnamelen);
546 status = cli_chkpath(cli, partpath);
547 if (!NT_STATUS_IS_OK(status)) {
548 status = cli_mkdir(cli, partpath);
549 if (!NT_STATUS_IS_OK(status)) {
550 SAFE_FREE(partpath);
551 SAFE_FREE(ffname);
552 DEBUG(0, ("Error mkdir %s\n", nt_errstr(status)));
553 return False;
554 } else {
555 DEBUG(3, ("mkdirhiering %s\n", partpath));
559 strlcat(partpath, "\\", fnamelen);
560 p = strtok_r(NULL, "/\\", &saveptr);
563 SAFE_FREE(partpath);
564 SAFE_FREE(ffname);
565 return True;
568 static int padit(char *buf, uint64_t bufsize, uint64_t padsize)
570 int berr= 0;
571 int bytestowrite;
573 DEBUG(5, ("Padding with %0.f zeros\n", (double)padsize));
574 memset(buf, 0, (size_t)bufsize);
575 while( !berr && padsize > 0 ) {
576 bytestowrite= (int)MIN(bufsize, padsize);
577 berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite;
578 padsize -= bytestowrite;
581 return berr;
584 static void do_setrattr(char *name, uint16 attr, int set)
586 uint16 oldattr;
587 NTSTATUS status;
589 if (!NT_STATUS_IS_OK(cli_getatr(cli, name, &oldattr, NULL, NULL))) {
590 return;
593 if (set == ATTRSET) {
594 attr |= oldattr;
595 } else {
596 attr = oldattr & ~attr;
599 status = cli_setatr(cli, name, attr, 0);
600 if (!NT_STATUS_IS_OK(status)) {
601 DEBUG(1, ("setatr failed: %s\n", nt_errstr(status)));
605 /****************************************************************************
606 append one remote file to the tar file
607 ***************************************************************************/
609 static NTSTATUS do_atar(const char *rname_in, char *lname,
610 struct file_info *finfo1)
612 uint16_t fnum = (uint16_t)-1;
613 uint64_t nread=0;
614 char ftype;
615 file_info2 finfo;
616 bool shallitime=True;
617 char *data = NULL;
618 int read_size = 65520;
619 int datalen=0;
620 char *rname = NULL;
621 TALLOC_CTX *ctx = talloc_stackframe();
622 NTSTATUS status = NT_STATUS_OK;
623 struct timespec tp_start;
625 clock_gettime_mono(&tp_start);
627 data = SMB_MALLOC_ARRAY(char, read_size);
628 if (!data) {
629 DEBUG(0,("do_atar: out of memory.\n"));
630 status = NT_STATUS_NO_MEMORY;
631 goto cleanup;
634 ftype = '0'; /* An ordinary file ... */
636 ZERO_STRUCT(finfo);
638 finfo.size = finfo1 -> size;
639 finfo.mode = finfo1 -> mode;
640 finfo.uid = finfo1 -> uid;
641 finfo.gid = finfo1 -> gid;
642 finfo.mtime_ts = finfo1 -> mtime_ts;
643 finfo.atime_ts = finfo1 -> atime_ts;
644 finfo.ctime_ts = finfo1 -> ctime_ts;
646 if (dry_run) {
647 DEBUG(3,("skipping file %s of size %12.0f bytes\n", finfo1->name,
648 (double)finfo.size));
649 shallitime=0;
650 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
651 ntarf++;
652 goto cleanup;
655 rname = clean_name(ctx, rname_in);
656 if (!rname) {
657 status = NT_STATUS_NO_MEMORY;
658 goto cleanup;
661 status = cli_open(cli, rname, O_RDONLY, DENY_NONE, &fnum);
662 if (!NT_STATUS_IS_OK(status)) {
663 DEBUG(0,("%s opening remote file %s (%s)\n",
664 nt_errstr(status),rname, client_get_cur_dir()));
665 goto cleanup;
668 finfo.name = smb_xstrdup(rname);
669 if (finfo.name == NULL) {
670 DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n"));
671 status = NT_STATUS_NO_MEMORY;
672 goto cleanup;
675 DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
677 if (tar_inc && !(finfo.mode & FILE_ATTRIBUTE_ARCHIVE)) {
678 DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
679 shallitime=0;
680 } else if (!tar_system && (finfo.mode & FILE_ATTRIBUTE_SYSTEM)) {
681 DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
682 shallitime=0;
683 } else if (!tar_hidden && (finfo.mode & FILE_ATTRIBUTE_HIDDEN)) {
684 DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
685 shallitime=0;
686 } else {
687 bool wrote_tar_header = False;
689 DEBUG(3,("getting file %s of size %.0f bytes as a tar file %s",
690 finfo.name, (double)finfo.size, lname));
692 do {
694 DEBUG(3,("nread=%.0f\n",(double)nread));
696 datalen = cli_read(cli, fnum, data, nread, read_size);
698 if (datalen == -1) {
699 DEBUG(0,("Error reading file %s : %s\n", rname, cli_errstr(cli)));
700 status = cli_nt_error(cli);
701 break;
704 nread += datalen;
706 /* Only if the first read succeeds, write out the tar header. */
707 if (!wrote_tar_header) {
708 /* write a tar header, don't bother with mode - just set to 100644 */
709 writetarheader(tarhandle, rname, finfo.size,
710 finfo.mtime_ts.tv_sec, "100644 \0", ftype);
711 wrote_tar_header = True;
714 /* if file size has increased since we made file size query, truncate
715 read so tar header for this file will be correct.
718 if (nread > finfo.size) {
719 datalen -= nread - finfo.size;
720 DEBUG(0,("File size change - truncating %s to %.0f bytes\n",
721 finfo.name, (double)finfo.size));
724 /* add received bits of file to buffer - dotarbuf will
725 * write out in 512 byte intervals */
727 if (dotarbuf(tarhandle,data,datalen) != datalen) {
728 DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
729 status = map_nt_error_from_unix(errno);
730 break;
733 if ( (datalen == 0) && (finfo.size != 0) ) {
734 status = NT_STATUS_UNSUCCESSFUL;
735 DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
736 break;
739 datalen=0;
740 } while ( nread < finfo.size );
742 if (wrote_tar_header) {
743 /* pad tar file with zero's if we couldn't get entire file */
744 if (nread < finfo.size) {
745 DEBUG(0, ("Didn't get entire file. size=%.0f, nread=%d\n",
746 (double)finfo.size, (int)nread));
747 if (padit(data, (uint64_t)sizeof(data), finfo.size - nread)) {
748 status = map_nt_error_from_unix(errno);
749 DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
753 /* round tar file to nearest block */
754 if (finfo.size % TBLOCK)
755 dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
757 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
758 ntarf++;
759 } else {
760 DEBUG(4, ("skipping %s - initial read failed (file was locked ?)\n", finfo.name));
761 shallitime=0;
762 status = NT_STATUS_UNSUCCESSFUL;
766 cli_close(cli, fnum);
767 fnum = -1;
769 if (shallitime) {
770 struct timespec tp_end;
771 int this_time;
773 /* if shallitime is true then we didn't skip */
774 if (tar_reset && !dry_run)
775 (void) do_setrattr(finfo.name, FILE_ATTRIBUTE_ARCHIVE, ATTRRESET);
777 clock_gettime_mono(&tp_end);
778 this_time = (tp_end.tv_sec - tp_start.tv_sec)*1000 + (tp_end.tv_nsec - tp_start.tv_nsec)/1000000;
779 get_total_time_ms += this_time;
780 get_total_size += finfo.size;
782 if (tar_noisy) {
783 DEBUG(0, ("%12.0f (%7.1f kb/s) %s\n",
784 (double)finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
785 finfo.name));
788 /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
789 DEBUG(3,("(%g kb/s) (average %g kb/s)\n",
790 finfo.size / MAX(0.001, (1.024*this_time)),
791 get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
794 cleanup:
796 if (fnum != (uint16_t)-1) {
797 cli_close(cli, fnum);
798 fnum = -1;
800 TALLOC_FREE(ctx);
801 SAFE_FREE(data);
802 return status;
805 /****************************************************************************
806 Append single file to tar file (or not)
807 ***************************************************************************/
809 static NTSTATUS do_tar(struct cli_state *cli_state, struct file_info *finfo,
810 const char *dir)
812 TALLOC_CTX *ctx = talloc_stackframe();
813 NTSTATUS status = NT_STATUS_OK;
815 if (strequal(finfo->name,"..") || strequal(finfo->name,"."))
816 return NT_STATUS_OK;
818 /* Is it on the exclude list ? */
819 if (!tar_excl && clipn) {
820 char *exclaim;
822 DEBUG(5, ("Excl: strlen(cur_dir) = %d\n", (int)strlen(client_get_cur_dir())));
824 exclaim = talloc_asprintf(ctx,
825 "%s\\%s",
826 client_get_cur_dir(),
827 finfo->name);
828 if (!exclaim) {
829 return NT_STATUS_NO_MEMORY;
832 DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
834 if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
835 (tar_re_search && mask_match_list(exclaim, cliplist, clipn, True))) {
836 DEBUG(3,("Skipping file %s\n", exclaim));
837 TALLOC_FREE(exclaim);
838 return NT_STATUS_OK;
840 TALLOC_FREE(exclaim);
843 if (finfo->mode & FILE_ATTRIBUTE_DIRECTORY) {
844 char *saved_curdir = NULL;
845 char *new_cd = NULL;
846 char *mtar_mask = NULL;
848 saved_curdir = talloc_strdup(ctx, client_get_cur_dir());
849 if (!saved_curdir) {
850 return NT_STATUS_NO_MEMORY;
853 DEBUG(5, ("strlen(cur_dir)=%d, \
854 strlen(finfo->name)=%d\nname=%s,cur_dir=%s\n",
855 (int)strlen(saved_curdir),
856 (int)strlen(finfo->name), finfo->name, saved_curdir));
858 new_cd = talloc_asprintf(ctx,
859 "%s%s\\",
860 client_get_cur_dir(),
861 finfo->name);
862 if (!new_cd) {
863 return NT_STATUS_NO_MEMORY;
865 client_set_cur_dir(new_cd);
867 DEBUG(5, ("Writing a dir, Name = %s\n", client_get_cur_dir()));
869 /* write a tar directory, don't bother with mode - just
870 * set it to 40755 */
871 writetarheader(tarhandle, client_get_cur_dir(), 0,
872 finfo->mtime_ts.tv_sec, "040755 \0", '5');
873 if (tar_noisy) {
874 DEBUG(0,(" directory %s\n",
875 client_get_cur_dir()));
877 ntarf++; /* Make sure we have a file on there */
878 mtar_mask = talloc_asprintf(ctx,
879 "%s*",
880 client_get_cur_dir());
881 if (!mtar_mask) {
882 return NT_STATUS_NO_MEMORY;
884 DEBUG(5, ("Doing list with mtar_mask: %s\n", mtar_mask));
885 status = do_list(mtar_mask, attribute, do_tar, False, True);
886 client_set_cur_dir(saved_curdir);
887 TALLOC_FREE(saved_curdir);
888 TALLOC_FREE(new_cd);
889 TALLOC_FREE(mtar_mask);
890 } else {
891 char *rname = talloc_asprintf(ctx,
892 "%s%s",
893 client_get_cur_dir(),
894 finfo->name);
895 if (!rname) {
896 return NT_STATUS_NO_MEMORY;
898 status = do_atar(rname,finfo->name,finfo);
899 TALLOC_FREE(rname);
901 return status;
904 /****************************************************************************
905 Convert from UNIX to DOS file names
906 ***************************************************************************/
908 static void unfixtarname(char *tptr, char *fp, int l, bool first)
910 /* remove '.' from start of file name, convert from unix /'s to
911 * dos \'s in path. Kill any absolute path names. But only if first!
914 DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
916 if (first) {
917 if (*fp == '.') {
918 fp++;
919 l--;
921 if (*fp == '\\' || *fp == '/') {
922 fp++;
923 l--;
925 if (l <= 0) {
926 return;
930 strlcpy(tptr, fp, l);
931 string_replace(tptr, '/', '\\');
934 /****************************************************************************
935 Move to the next block in the buffer, which may mean read in another set of
936 blocks. FIXME, we should allow more than one block to be skipped.
937 ****************************************************************************/
939 static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
941 int bufread, total = 0;
943 DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp));
944 *bufferp += TBLOCK;
945 total = TBLOCK;
947 if (*bufferp >= (ltarbuf + bufsiz)) {
949 DEBUG(5, ("Reading more data into ltarbuf ...\n"));
952 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>
953 * Fixes bug where read can return short if coming from
954 * a pipe.
957 bufread = read(tarhandle, ltarbuf, bufsiz);
958 total = bufread;
960 while (total < bufsiz) {
961 if (bufread < 0) { /* An error, return false */
962 return (total > 0 ? -2 : bufread);
964 if (bufread == 0) {
965 if (total <= 0) {
966 return -2;
968 break;
970 bufread = read(tarhandle, &ltarbuf[total], bufsiz - total);
971 total += bufread;
974 DEBUG(5, ("Total bytes read ... %i\n", total));
976 *bufferp = ltarbuf;
979 return(total);
982 /* Skip a file, even if it includes a long file name? */
983 static int skip_file(int skipsize)
985 int dsize = skipsize;
987 DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
989 /* FIXME, we should skip more than one block at a time */
991 while (dsize > 0) {
992 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
993 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
994 return(False);
996 dsize -= TBLOCK;
999 return(True);
1002 /*************************************************************
1003 Get a file from the tar file and store it.
1004 When this is called, tarbuf already contains the first
1005 file block. This is a bit broken & needs fixing.
1006 **************************************************************/
1008 static int get_file(file_info2 finfo)
1010 uint16_t fnum = (uint16_t) -1;
1011 int pos = 0, dsize = 0, bpos = 0;
1012 uint64_t rsize = 0;
1013 NTSTATUS status;
1015 DEBUG(5, ("get_file: file: %s, size %.0f\n", finfo.name, (double)finfo.size));
1017 if (!ensurepath(finfo.name)) {
1018 DEBUG(0, ("abandoning restore\n"));
1019 return False;
1022 status = cli_open(cli, finfo.name, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE, &fnum);
1023 if (!NT_STATUS_IS_OK(status)) {
1024 DEBUG(0, ("abandoning restore\n"));
1025 return False;
1028 /* read the blocks from the tar file and write to the remote file */
1030 rsize = finfo.size; /* This is how much to write */
1032 while (rsize > 0) {
1034 /* We can only write up to the end of the buffer */
1035 dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, 65520); /* Calculate the size to write */
1036 dsize = MIN(dsize, rsize); /* Should be only what is left */
1037 DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos));
1039 status = cli_writeall(cli, fnum, 0,
1040 (uint8_t *)(buffer_p + bpos), pos,
1041 dsize, NULL);
1042 if (!NT_STATUS_IS_OK(status)) {
1043 DEBUG(0, ("Error writing remote file: %s\n",
1044 nt_errstr(status)));
1045 return 0;
1048 rsize -= dsize;
1049 pos += dsize;
1051 /* Now figure out how much to move in the buffer */
1053 /* FIXME, we should skip more than one block at a time */
1055 /* First, skip any initial part of the part written that is left over */
1056 /* from the end of the first TBLOCK */
1058 if ((bpos) && ((bpos + dsize) >= TBLOCK)) {
1059 dsize -= (TBLOCK - bpos); /* Get rid of the end of the first block */
1060 bpos = 0;
1062 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) { /* and skip the block */
1063 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1064 return False;
1069 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>.
1070 * If the file being extracted is an exact multiple of
1071 * TBLOCK bytes then we don't want to extract the next
1072 * block from the tarfile here, as it will be done in
1073 * the caller of get_file().
1076 while (((rsize != 0) && (dsize >= TBLOCK)) ||
1077 ((rsize == 0) && (dsize > TBLOCK))) {
1079 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1080 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1081 return False;
1084 dsize -= TBLOCK;
1086 bpos = dsize;
1089 /* Now close the file ... */
1090 status = cli_close(cli, fnum);
1091 if (!NT_STATUS_IS_OK(status)) {
1092 DEBUG(0, ("Error %s closing remote file\n",
1093 nt_errstr(status)));
1094 return(False);
1097 /* Now we update the creation date ... */
1098 DEBUG(5, ("Updating creation date on %s\n", finfo.name));
1100 if (!NT_STATUS_IS_OK(cli_setatr(cli, finfo.name, finfo.mode, finfo.mtime_ts.tv_sec))) {
1101 if (tar_real_noisy) {
1102 DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
1103 /*return(False); */ /* Ignore, as Win95 does not allow changes */
1107 ntarf++;
1108 DEBUG(0, ("restore tar file %s of size %.0f bytes\n", finfo.name, (double)finfo.size));
1109 return(True);
1112 /* Create a directory. We just ensure that the path exists and return as there
1113 is no file associated with a directory
1115 static int get_dir(file_info2 finfo)
1117 DEBUG(0, ("restore directory %s\n", finfo.name));
1119 if (!ensurepath(finfo.name)) {
1120 DEBUG(0, ("Problems creating directory\n"));
1121 return(False);
1123 ntarf++;
1124 return(True);
1127 /* Get a file with a long file name ... first file has file name, next file
1128 has the data. We only want the long file name, as the loop in do_tarput
1129 will deal with the rest.
1131 static char *get_longfilename(file_info2 finfo)
1133 /* finfo.size here is the length of the filename as written by the "/./@LongLink" name
1134 * header call. */
1135 int namesize = finfo.size + strlen(client_get_cur_dir()) + 2;
1136 char *longname = (char *)SMB_MALLOC(namesize);
1137 int offset = 0, left = finfo.size;
1138 bool first = True;
1140 DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
1141 DEBUG(5, ("Len = %.0f\n", (double)finfo.size));
1143 if (longname == NULL) {
1144 DEBUG(0, ("could not allocate buffer of size %d for longname\n", namesize));
1145 return(NULL);
1148 /* First, add cur_dir to the long file name */
1150 if (strlen(client_get_cur_dir()) > 0) {
1151 strncpy(longname, client_get_cur_dir(), namesize);
1152 offset = strlen(client_get_cur_dir());
1155 /* Loop through the blocks picking up the name */
1157 while (left > 0) {
1158 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1159 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1160 SAFE_FREE(longname);
1161 return(NULL);
1164 unfixtarname(longname + offset, buffer_p,
1165 namesize - offset, first--);
1166 DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
1168 offset += TBLOCK;
1169 left -= TBLOCK;
1172 return(longname);
1175 static void do_tarput(void)
1177 file_info2 finfo;
1178 struct timespec tp_start;
1179 char *longfilename = NULL, linkflag;
1180 int skip = False;
1182 ZERO_STRUCT(finfo);
1184 clock_gettime_mono(&tp_start);
1185 DEBUG(5, ("RJS do_tarput called ...\n"));
1187 buffer_p = tarbuf + tbufsiz; /* init this to force first read */
1189 /* Now read through those files ... */
1190 while (True) {
1191 /* Get us to the next block, or the first block first time around */
1192 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1193 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1194 SAFE_FREE(longfilename);
1195 return;
1198 DEBUG(5, ("Reading the next header ...\n"));
1200 switch (readtarheader((union hblock *) buffer_p,
1201 &finfo, client_get_cur_dir())) {
1202 case -2: /* Hmm, not good, but not fatal */
1203 DEBUG(0, ("Skipping %s...\n", finfo.name));
1204 if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) && !skip_file(finfo.size)) {
1205 DEBUG(0, ("Short file, bailing out...\n"));
1206 SAFE_FREE(longfilename);
1207 return;
1209 break;
1211 case -1:
1212 DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
1213 SAFE_FREE(longfilename);
1214 return;
1216 case 0: /* chksum is zero - looks like an EOF */
1217 DEBUG(0, ("tar: restored %d files and directories\n", ntarf));
1218 SAFE_FREE(longfilename);
1219 return; /* Hmmm, bad here ... */
1221 default:
1222 /* No action */
1223 break;
1226 /* Now, do we have a long file name? */
1227 if (longfilename != NULL) {
1228 SAFE_FREE(finfo.name); /* Free the space already allocated */
1229 finfo.name = longfilename;
1230 longfilename = NULL;
1233 /* Well, now we have a header, process the file ... */
1234 /* Should we skip the file? We have the long name as well here */
1235 skip = clipn && ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl) ||
1236 (tar_re_search && mask_match_list(finfo.name, cliplist, clipn, True)));
1238 DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
1239 if (skip) {
1240 skip_file(finfo.size);
1241 continue;
1244 /* We only get this far if we should process the file */
1245 linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
1246 switch (linkflag) {
1247 case '0': /* Should use symbolic names--FIXME */
1249 * Skip to the next block first, so we can get the file, FIXME, should
1250 * be in get_file ...
1251 * The 'finfo.size != 0' fix is from Bob Boehmer <boehmer@worldnet.att.net>
1252 * Fixes bug where file size in tarfile is zero.
1254 if ((finfo.size != 0) && next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1255 DEBUG(0, ("Short file, bailing out...\n"));
1256 return;
1258 if (!get_file(finfo)) {
1259 DEBUG(0, ("Abandoning restore\n"));
1260 return;
1262 break;
1263 case '5':
1264 if (!get_dir(finfo)) {
1265 DEBUG(0, ("Abandoning restore \n"));
1266 return;
1268 break;
1269 case 'L':
1270 SAFE_FREE(longfilename);
1271 longfilename = get_longfilename(finfo);
1272 if (!longfilename) {
1273 DEBUG(0, ("abandoning restore\n"));
1274 return;
1276 DEBUG(5, ("Long file name: %s\n", longfilename));
1277 break;
1279 default:
1280 skip_file(finfo.size); /* Don't handle these yet */
1281 break;
1287 * samba interactive commands
1290 /****************************************************************************
1291 Blocksize command
1292 ***************************************************************************/
1294 int cmd_block(void)
1296 TALLOC_CTX *ctx = talloc_tos();
1297 char *buf;
1298 int block;
1300 if (!next_token_talloc(ctx, (const char **)&cmd_ptr,&buf,NULL)) {
1301 DEBUG(0, ("blocksize <n>\n"));
1302 return 1;
1305 block=atoi(buf);
1306 if (block < 0 || block > 65535) {
1307 DEBUG(0, ("blocksize out of range"));
1308 return 1;
1311 blocksize=block;
1312 DEBUG(2,("blocksize is now %d\n", blocksize));
1313 return 0;
1316 /****************************************************************************
1317 command to set incremental / reset mode
1318 ***************************************************************************/
1320 int cmd_tarmode(void)
1322 TALLOC_CTX *ctx = talloc_tos();
1323 char *buf;
1325 while (next_token_talloc(ctx, (const char **)&cmd_ptr,&buf,NULL)) {
1326 if (strequal(buf, "full"))
1327 tar_inc=False;
1328 else if (strequal(buf, "inc"))
1329 tar_inc=True;
1330 else if (strequal(buf, "reset"))
1331 tar_reset=True;
1332 else if (strequal(buf, "noreset"))
1333 tar_reset=False;
1334 else if (strequal(buf, "system"))
1335 tar_system=True;
1336 else if (strequal(buf, "nosystem"))
1337 tar_system=False;
1338 else if (strequal(buf, "hidden"))
1339 tar_hidden=True;
1340 else if (strequal(buf, "nohidden"))
1341 tar_hidden=False;
1342 else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
1343 tar_noisy=True;
1344 else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
1345 tar_noisy=False;
1346 else
1347 DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
1348 TALLOC_FREE(buf);
1351 DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
1352 tar_inc ? "incremental" : "full",
1353 tar_system ? "system" : "nosystem",
1354 tar_hidden ? "hidden" : "nohidden",
1355 tar_reset ? "reset" : "noreset",
1356 tar_noisy ? "verbose" : "quiet"));
1357 return 0;
1360 /****************************************************************************
1361 Feeble attrib command
1362 ***************************************************************************/
1364 int cmd_setmode(void)
1366 TALLOC_CTX *ctx = talloc_tos();
1367 char *q;
1368 char *buf;
1369 char *fname = NULL;
1370 uint16 attra[2];
1371 int direct=1;
1373 attra[0] = attra[1] = 0;
1375 if (!next_token_talloc(ctx, (const char **)&cmd_ptr,&buf,NULL)) {
1376 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1377 return 1;
1380 fname = talloc_asprintf(ctx,
1381 "%s%s",
1382 client_get_cur_dir(),
1383 buf);
1384 if (!fname) {
1385 return 1;
1388 while (next_token_talloc(ctx, (const char **)&cmd_ptr,&buf,NULL)) {
1389 q=buf;
1391 while(*q) {
1392 switch (*q++) {
1393 case '+':
1394 direct=1;
1395 break;
1396 case '-':
1397 direct=0;
1398 break;
1399 case 'r':
1400 attra[direct]|=FILE_ATTRIBUTE_READONLY;
1401 break;
1402 case 'h':
1403 attra[direct]|=FILE_ATTRIBUTE_HIDDEN;
1404 break;
1405 case 's':
1406 attra[direct]|=FILE_ATTRIBUTE_SYSTEM;
1407 break;
1408 case 'a':
1409 attra[direct]|=FILE_ATTRIBUTE_ARCHIVE;
1410 break;
1411 default:
1412 DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1413 return 1;
1418 if (attra[ATTRSET]==0 && attra[ATTRRESET]==0) {
1419 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1420 return 1;
1423 DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1424 do_setrattr(fname, attra[ATTRSET], ATTRSET);
1425 do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
1426 return 0;
1430 Convert list of tokens to array; dependent on above routine.
1431 Uses the global cmd_ptr from above - bit of a hack.
1434 static char **toktocliplist(int *ctok, const char *sep)
1436 char *s=(char *)cmd_ptr;
1437 int ictok=0;
1438 char **ret, **iret;
1440 if (!sep)
1441 sep = " \t\n\r";
1443 while(*s && strchr_m(sep,*s))
1444 s++;
1446 /* nothing left? */
1447 if (!*s)
1448 return(NULL);
1450 do {
1451 ictok++;
1452 while(*s && (!strchr_m(sep,*s)))
1453 s++;
1454 while(*s && strchr_m(sep,*s))
1455 *s++=0;
1456 } while(*s);
1458 *ctok=ictok;
1459 s=(char *)cmd_ptr;
1461 if (!(ret=iret=SMB_MALLOC_ARRAY(char *,ictok+1)))
1462 return NULL;
1464 while(ictok--) {
1465 *iret++=s;
1466 if (ictok > 0) {
1467 while(*s++)
1469 while(!*s)
1470 s++;
1474 ret[*ctok] = NULL;
1475 return ret;
1478 /****************************************************************************
1479 Principal command for creating / extracting
1480 ***************************************************************************/
1482 int cmd_tar(void)
1484 TALLOC_CTX *ctx = talloc_tos();
1485 char *buf;
1486 char **argl = NULL;
1487 int argcl = 0;
1488 int ret;
1490 if (!next_token_talloc(ctx, (const char **)&cmd_ptr,&buf,NULL)) {
1491 DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
1492 return 1;
1495 argl=toktocliplist(&argcl, NULL);
1496 if (!tar_parseargs(argcl, argl, buf, 0)) {
1497 SAFE_FREE(argl);
1498 return 1;
1501 ret = process_tar();
1502 SAFE_FREE(argl);
1503 return ret;
1506 /****************************************************************************
1507 Command line (option) version
1508 ***************************************************************************/
1510 int process_tar(void)
1512 TALLOC_CTX *ctx = talloc_tos();
1513 int rc = 0;
1514 initarbuf();
1515 switch(tar_type) {
1516 case 'x':
1518 #if 0
1519 do_tarput2();
1520 #else
1521 do_tarput();
1522 #endif
1523 SAFE_FREE(tarbuf);
1524 close(tarhandle);
1525 break;
1526 case 'r':
1527 case 'c':
1528 if (clipn && tar_excl) {
1529 int i;
1530 char *tarmac = NULL;
1532 for (i=0; i<clipn; i++) {
1533 DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
1535 if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1536 *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1539 if (strrchr_m(cliplist[i], '\\')) {
1540 char *p;
1541 char saved_char;
1542 char *saved_dir = talloc_strdup(ctx,
1543 client_get_cur_dir());
1544 if (!saved_dir) {
1545 return 1;
1548 if (*cliplist[i]=='\\') {
1549 tarmac = talloc_strdup(ctx,
1550 cliplist[i]);
1551 } else {
1552 tarmac = talloc_asprintf(ctx,
1553 "%s%s",
1554 client_get_cur_dir(),
1555 cliplist[i]);
1557 if (!tarmac) {
1558 return 1;
1561 * Strip off the last \\xxx
1562 * xxx element of tarmac to set
1563 * it as current directory.
1565 p = strrchr_m(tarmac, '\\');
1566 if (!p) {
1567 return 1;
1569 saved_char = p[1];
1570 p[1] = '\0';
1572 client_set_cur_dir(tarmac);
1575 * Restore the character we
1576 * just replaced to
1577 * put the pathname
1578 * back as it was.
1580 p[1] = saved_char;
1582 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1583 do_list(tarmac,attribute,do_tar, False, True);
1585 client_set_cur_dir(saved_dir);
1587 TALLOC_FREE(saved_dir);
1588 TALLOC_FREE(tarmac);
1589 } else {
1590 tarmac = talloc_asprintf(ctx,
1591 "%s%s",
1592 client_get_cur_dir(),
1593 cliplist[i]);
1594 if (!tarmac) {
1595 return 1;
1597 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1598 do_list(tarmac,attribute,do_tar, False, True);
1599 TALLOC_FREE(tarmac);
1602 } else {
1603 char *mask = talloc_asprintf(ctx,
1604 "%s\\*",
1605 client_get_cur_dir());
1606 if (!mask) {
1607 return 1;
1609 DEBUG(5, ("process_tar, do_list with mask: %s\n", mask));
1610 do_list(mask,attribute,do_tar,False, True);
1611 TALLOC_FREE(mask);
1614 if (ntarf) {
1615 dotareof(tarhandle);
1617 close(tarhandle);
1618 SAFE_FREE(tarbuf);
1620 DEBUG(0, ("tar: dumped %d files and directories\n", ntarf));
1621 DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf));
1622 break;
1625 if (must_free_cliplist) {
1626 int i;
1627 for (i = 0; i < clipn; ++i) {
1628 SAFE_FREE(cliplist[i]);
1630 SAFE_FREE(cliplist);
1631 cliplist = NULL;
1632 clipn = 0;
1633 must_free_cliplist = False;
1635 return rc;
1638 /****************************************************************************
1639 Find a token (filename) in a clip list
1640 ***************************************************************************/
1642 static int clipfind(char **aret, int ret, char *tok)
1644 if (aret==NULL)
1645 return 0;
1647 /* ignore leading slashes or dots in token */
1648 while(strchr_m("/\\.", *tok))
1649 tok++;
1651 while(ret--) {
1652 char *pkey=*aret++;
1654 /* ignore leading slashes or dots in list */
1655 while(strchr_m("/\\.", *pkey))
1656 pkey++;
1658 if (!strslashcmp(pkey, tok))
1659 return 1;
1661 return 0;
1664 /****************************************************************************
1665 Read list of files to include from the file and initialize cliplist
1666 accordingly.
1667 ***************************************************************************/
1669 static int read_inclusion_file(char *filename)
1671 XFILE *inclusion = NULL;
1672 char buf[PATH_MAX + 1];
1673 char *inclusion_buffer = NULL;
1674 int inclusion_buffer_size = 0;
1675 int inclusion_buffer_sofar = 0;
1676 char *p;
1677 char *tmpstr;
1678 int i;
1679 int error = 0;
1681 clipn = 0;
1682 buf[PATH_MAX] = '\0'; /* guarantee null-termination */
1683 if ((inclusion = x_fopen(filename, O_RDONLY, 0)) == NULL) {
1684 /* XXX It would be better to include a reason for failure, but without
1685 * autoconf, it's hard to use strerror, sys_errlist, etc.
1687 DEBUG(0,("Unable to open inclusion file %s\n", filename));
1688 return 0;
1691 while ((! error) && (x_fgets(buf, sizeof(buf)-1, inclusion))) {
1692 if (inclusion_buffer == NULL) {
1693 inclusion_buffer_size = 1024;
1694 if ((inclusion_buffer = (char *)SMB_MALLOC(inclusion_buffer_size)) == NULL) {
1695 DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1696 error = 1;
1697 break;
1701 if (buf[strlen(buf)-1] == '\n') {
1702 buf[strlen(buf)-1] = '\0';
1705 if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1706 inclusion_buffer_size *= 2;
1707 inclusion_buffer = (char *)SMB_REALLOC(inclusion_buffer,inclusion_buffer_size);
1708 if (!inclusion_buffer) {
1709 DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1710 inclusion_buffer_size));
1711 error = 1;
1712 break;
1716 strlcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
1717 inclusion_buffer_sofar += strlen(buf) + 1;
1718 clipn++;
1720 x_fclose(inclusion);
1722 if (! error) {
1723 /* Allocate an array of clipn + 1 char*'s for cliplist */
1724 cliplist = SMB_MALLOC_ARRAY(char *, clipn + 1);
1725 if (cliplist == NULL) {
1726 DEBUG(0,("failure allocating memory for cliplist\n"));
1727 error = 1;
1728 } else {
1729 cliplist[clipn] = NULL;
1730 p = inclusion_buffer;
1731 for (i = 0; (! error) && (i < clipn); i++) {
1732 /* set current item to NULL so array will be null-terminated even if
1733 * malloc fails below. */
1734 cliplist[i] = NULL;
1735 if ((tmpstr = (char *)SMB_MALLOC(strlen(p)+1)) == NULL) {
1736 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
1737 error = 1;
1738 } else {
1739 unfixtarname(tmpstr, p, strlen(p) + 1, True);
1740 cliplist[i] = tmpstr;
1741 if ((p = strchr_m(p, '\000')) == NULL) {
1742 DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1743 abort();
1746 ++p;
1748 must_free_cliplist = True;
1752 SAFE_FREE(inclusion_buffer);
1753 if (error) {
1754 if (cliplist) {
1755 char **pp;
1756 /* We know cliplist is always null-terminated */
1757 for (pp = cliplist; *pp; ++pp) {
1758 SAFE_FREE(*pp);
1760 SAFE_FREE(cliplist);
1761 cliplist = NULL;
1762 must_free_cliplist = False;
1764 return 0;
1767 /* cliplist and its elements are freed at the end of process_tar. */
1768 return 1;
1771 /****************************************************************************
1772 Parse tar arguments. Sets tar_type, tar_excl, etc.
1773 ***************************************************************************/
1775 int tar_parseargs(int argc, char *argv[], const char *Optarg, int Optind)
1777 int newOptind = Optind;
1778 char tar_clipfl='\0';
1780 /* Reset back to defaults - could be from interactive version
1781 * reset mode and archive mode left as they are though
1783 tar_type='\0';
1784 tar_excl=True;
1785 dry_run=False;
1787 while (*Optarg) {
1788 switch(*Optarg++) {
1789 case 'c':
1790 tar_type='c';
1791 break;
1792 case 'x':
1793 if (tar_type=='c') {
1794 printf("Tar must be followed by only one of c or x.\n");
1795 return 0;
1797 tar_type='x';
1798 break;
1799 case 'b':
1800 if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1801 DEBUG(0,("Option b must be followed by valid blocksize\n"));
1802 return 0;
1803 } else {
1804 Optind++;
1805 newOptind++;
1807 break;
1808 case 'g':
1809 tar_inc=True;
1810 break;
1811 case 'N':
1812 if (Optind>=argc) {
1813 DEBUG(0,("Option N must be followed by valid file name\n"));
1814 return 0;
1815 } else {
1816 SMB_STRUCT_STAT stbuf;
1818 if (sys_stat(argv[Optind], &stbuf,
1819 false) == 0) {
1820 newer_than = convert_timespec_to_time_t(
1821 stbuf.st_ex_mtime);
1822 DEBUG(1,("Getting files newer than %s",
1823 time_to_asc(newer_than)));
1824 newOptind++;
1825 Optind++;
1826 } else {
1827 DEBUG(0,("Error setting newer-than time\n"));
1828 return 0;
1831 break;
1832 case 'a':
1833 tar_reset=True;
1834 break;
1835 case 'q':
1836 tar_noisy=False;
1837 break;
1838 case 'I':
1839 if (tar_clipfl) {
1840 DEBUG(0,("Only one of I,X,F must be specified\n"));
1841 return 0;
1843 tar_clipfl='I';
1844 break;
1845 case 'X':
1846 if (tar_clipfl) {
1847 DEBUG(0,("Only one of I,X,F must be specified\n"));
1848 return 0;
1850 tar_clipfl='X';
1851 break;
1852 case 'F':
1853 if (tar_clipfl) {
1854 DEBUG(0,("Only one of I,X,F must be specified\n"));
1855 return 0;
1857 tar_clipfl='F';
1858 break;
1859 case 'r':
1860 DEBUG(0, ("tar_re_search set\n"));
1861 tar_re_search = True;
1862 break;
1863 case 'n':
1864 if (tar_type == 'c') {
1865 DEBUG(0, ("dry_run set\n"));
1866 dry_run = True;
1867 } else {
1868 DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1869 return 0;
1871 break;
1872 default:
1873 DEBUG(0,("Unknown tar option\n"));
1874 return 0;
1878 if (!tar_type) {
1879 printf("Option T must be followed by one of c or x.\n");
1880 return 0;
1883 /* tar_excl is true if cliplist lists files to be included.
1884 * Both 'I' and 'F' mean include. */
1885 tar_excl=tar_clipfl!='X';
1887 if (tar_clipfl=='F') {
1888 if (argc-Optind-1 != 1) {
1889 DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1890 return 0;
1892 newOptind++;
1893 /* Optind points at the tar output file, Optind+1 at the inclusion file. */
1894 if (! read_inclusion_file(argv[Optind+1])) {
1895 return 0;
1897 } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
1898 char *tmpstr;
1899 char **tmplist;
1900 int clipcount;
1902 cliplist=argv+Optind+1;
1903 clipn=argc-Optind-1;
1904 clipcount = clipn;
1906 if ((tmplist=SMB_MALLOC_ARRAY(char *,clipn)) == NULL) {
1907 DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n", clipn));
1908 return 0;
1911 for (clipcount = 0; clipcount < clipn; clipcount++) {
1913 DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1915 if ((tmpstr = (char *)SMB_MALLOC(strlen(cliplist[clipcount])+1)) == NULL) {
1916 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", clipcount));
1917 SAFE_FREE(tmplist);
1918 return 0;
1921 unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
1922 tmplist[clipcount] = tmpstr;
1923 DEBUG(5, ("Processed an item, %s\n", tmpstr));
1925 DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1928 cliplist = tmplist;
1929 must_free_cliplist = True;
1931 newOptind += clipn;
1934 if (Optind+1<argc && tar_re_search && tar_clipfl != 'F') {
1935 /* Doing regular expression seaches not from an inclusion file. */
1936 clipn=argc-Optind-1;
1937 cliplist=argv+Optind+1;
1938 newOptind += clipn;
1941 if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1942 /* Sets tar handle to either 0 or 1, as appropriate */
1943 tarhandle=(tar_type=='c');
1945 * Make sure that dbf points to stderr if we are using stdout for
1946 * tar output
1948 if (tarhandle == 1) {
1949 setup_logging("smbclient", DEBUG_STDERR);
1951 if (!argv[Optind]) {
1952 DEBUG(0,("Must specify tar filename\n"));
1953 return 0;
1955 if (!strcmp(argv[Optind], "-")) {
1956 newOptind++;
1959 } else {
1960 if (tar_type=='c' && dry_run) {
1961 tarhandle=-1;
1962 } else if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1)
1963 || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0)) {
1964 DEBUG(0,("Error opening local file %s - %s\n", argv[Optind], strerror(errno)));
1965 return(0);
1967 newOptind++;
1970 return newOptind;