s4:libcli/raw: s/SMBchkpth/SMBcheckpath
[Samba/gebeck_regimport.git] / source3 / client / clitar.c
bloba5de8ebafe58720ddc21ce736c0ff93f7bd944dc
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 status = cli_nt_error(cli);
700 DEBUG(0,("Error reading file %s : %s\n",
701 rname, nt_errstr(status)));
702 break;
705 nread += datalen;
707 /* Only if the first read succeeds, write out the tar header. */
708 if (!wrote_tar_header) {
709 /* write a tar header, don't bother with mode - just set to 100644 */
710 writetarheader(tarhandle, rname, finfo.size,
711 finfo.mtime_ts.tv_sec, "100644 \0", ftype);
712 wrote_tar_header = True;
715 /* if file size has increased since we made file size query, truncate
716 read so tar header for this file will be correct.
719 if (nread > finfo.size) {
720 datalen -= nread - finfo.size;
721 DEBUG(0,("File size change - truncating %s to %.0f bytes\n",
722 finfo.name, (double)finfo.size));
725 /* add received bits of file to buffer - dotarbuf will
726 * write out in 512 byte intervals */
728 if (dotarbuf(tarhandle,data,datalen) != datalen) {
729 DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
730 status = map_nt_error_from_unix(errno);
731 break;
734 if ( (datalen == 0) && (finfo.size != 0) ) {
735 status = NT_STATUS_UNSUCCESSFUL;
736 DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
737 break;
740 datalen=0;
741 } while ( nread < finfo.size );
743 if (wrote_tar_header) {
744 /* pad tar file with zero's if we couldn't get entire file */
745 if (nread < finfo.size) {
746 DEBUG(0, ("Didn't get entire file. size=%.0f, nread=%d\n",
747 (double)finfo.size, (int)nread));
748 if (padit(data, (uint64_t)sizeof(data), finfo.size - nread)) {
749 status = map_nt_error_from_unix(errno);
750 DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
754 /* round tar file to nearest block */
755 if (finfo.size % TBLOCK)
756 dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
758 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
759 ntarf++;
760 } else {
761 DEBUG(4, ("skipping %s - initial read failed (file was locked ?)\n", finfo.name));
762 shallitime=0;
763 status = NT_STATUS_UNSUCCESSFUL;
767 cli_close(cli, fnum);
768 fnum = -1;
770 if (shallitime) {
771 struct timespec tp_end;
772 int this_time;
774 /* if shallitime is true then we didn't skip */
775 if (tar_reset && !dry_run)
776 (void) do_setrattr(finfo.name, FILE_ATTRIBUTE_ARCHIVE, ATTRRESET);
778 clock_gettime_mono(&tp_end);
779 this_time = (tp_end.tv_sec - tp_start.tv_sec)*1000 + (tp_end.tv_nsec - tp_start.tv_nsec)/1000000;
780 get_total_time_ms += this_time;
781 get_total_size += finfo.size;
783 if (tar_noisy) {
784 DEBUG(0, ("%12.0f (%7.1f kb/s) %s\n",
785 (double)finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
786 finfo.name));
789 /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
790 DEBUG(3,("(%g kb/s) (average %g kb/s)\n",
791 finfo.size / MAX(0.001, (1.024*this_time)),
792 get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
795 cleanup:
797 if (fnum != (uint16_t)-1) {
798 cli_close(cli, fnum);
799 fnum = -1;
801 TALLOC_FREE(ctx);
802 SAFE_FREE(data);
803 return status;
806 /****************************************************************************
807 Append single file to tar file (or not)
808 ***************************************************************************/
810 static NTSTATUS do_tar(struct cli_state *cli_state, struct file_info *finfo,
811 const char *dir)
813 TALLOC_CTX *ctx = talloc_stackframe();
814 NTSTATUS status = NT_STATUS_OK;
816 if (strequal(finfo->name,"..") || strequal(finfo->name,"."))
817 return NT_STATUS_OK;
819 /* Is it on the exclude list ? */
820 if (!tar_excl && clipn) {
821 char *exclaim;
823 DEBUG(5, ("Excl: strlen(cur_dir) = %d\n", (int)strlen(client_get_cur_dir())));
825 exclaim = talloc_asprintf(ctx,
826 "%s\\%s",
827 client_get_cur_dir(),
828 finfo->name);
829 if (!exclaim) {
830 return NT_STATUS_NO_MEMORY;
833 DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
835 if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
836 (tar_re_search && mask_match_list(exclaim, cliplist, clipn, True))) {
837 DEBUG(3,("Skipping file %s\n", exclaim));
838 TALLOC_FREE(exclaim);
839 return NT_STATUS_OK;
841 TALLOC_FREE(exclaim);
844 if (finfo->mode & FILE_ATTRIBUTE_DIRECTORY) {
845 char *saved_curdir = NULL;
846 char *new_cd = NULL;
847 char *mtar_mask = NULL;
849 saved_curdir = talloc_strdup(ctx, client_get_cur_dir());
850 if (!saved_curdir) {
851 return NT_STATUS_NO_MEMORY;
854 DEBUG(5, ("strlen(cur_dir)=%d, \
855 strlen(finfo->name)=%d\nname=%s,cur_dir=%s\n",
856 (int)strlen(saved_curdir),
857 (int)strlen(finfo->name), finfo->name, saved_curdir));
859 new_cd = talloc_asprintf(ctx,
860 "%s%s\\",
861 client_get_cur_dir(),
862 finfo->name);
863 if (!new_cd) {
864 return NT_STATUS_NO_MEMORY;
866 client_set_cur_dir(new_cd);
868 DEBUG(5, ("Writing a dir, Name = %s\n", client_get_cur_dir()));
870 /* write a tar directory, don't bother with mode - just
871 * set it to 40755 */
872 writetarheader(tarhandle, client_get_cur_dir(), 0,
873 finfo->mtime_ts.tv_sec, "040755 \0", '5');
874 if (tar_noisy) {
875 DEBUG(0,(" directory %s\n",
876 client_get_cur_dir()));
878 ntarf++; /* Make sure we have a file on there */
879 mtar_mask = talloc_asprintf(ctx,
880 "%s*",
881 client_get_cur_dir());
882 if (!mtar_mask) {
883 return NT_STATUS_NO_MEMORY;
885 DEBUG(5, ("Doing list with mtar_mask: %s\n", mtar_mask));
886 status = do_list(mtar_mask, attribute, do_tar, False, True);
887 client_set_cur_dir(saved_curdir);
888 TALLOC_FREE(saved_curdir);
889 TALLOC_FREE(new_cd);
890 TALLOC_FREE(mtar_mask);
891 } else {
892 char *rname = talloc_asprintf(ctx,
893 "%s%s",
894 client_get_cur_dir(),
895 finfo->name);
896 if (!rname) {
897 return NT_STATUS_NO_MEMORY;
899 status = do_atar(rname,finfo->name,finfo);
900 TALLOC_FREE(rname);
902 return status;
905 /****************************************************************************
906 Convert from UNIX to DOS file names
907 ***************************************************************************/
909 static void unfixtarname(char *tptr, char *fp, int l, bool first)
911 /* remove '.' from start of file name, convert from unix /'s to
912 * dos \'s in path. Kill any absolute path names. But only if first!
915 DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
917 if (first) {
918 if (*fp == '.') {
919 fp++;
920 l--;
922 if (*fp == '\\' || *fp == '/') {
923 fp++;
924 l--;
926 if (l <= 0) {
927 return;
931 strlcpy(tptr, fp, l);
932 string_replace(tptr, '/', '\\');
935 /****************************************************************************
936 Move to the next block in the buffer, which may mean read in another set of
937 blocks. FIXME, we should allow more than one block to be skipped.
938 ****************************************************************************/
940 static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
942 int bufread, total = 0;
944 DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp));
945 *bufferp += TBLOCK;
946 total = TBLOCK;
948 if (*bufferp >= (ltarbuf + bufsiz)) {
950 DEBUG(5, ("Reading more data into ltarbuf ...\n"));
953 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>
954 * Fixes bug where read can return short if coming from
955 * a pipe.
958 bufread = read(tarhandle, ltarbuf, bufsiz);
959 total = bufread;
961 while (total < bufsiz) {
962 if (bufread < 0) { /* An error, return false */
963 return (total > 0 ? -2 : bufread);
965 if (bufread == 0) {
966 if (total <= 0) {
967 return -2;
969 break;
971 bufread = read(tarhandle, &ltarbuf[total], bufsiz - total);
972 total += bufread;
975 DEBUG(5, ("Total bytes read ... %i\n", total));
977 *bufferp = ltarbuf;
980 return(total);
983 /* Skip a file, even if it includes a long file name? */
984 static int skip_file(int skipsize)
986 int dsize = skipsize;
988 DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
990 /* FIXME, we should skip more than one block at a time */
992 while (dsize > 0) {
993 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
994 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
995 return(False);
997 dsize -= TBLOCK;
1000 return(True);
1003 /*************************************************************
1004 Get a file from the tar file and store it.
1005 When this is called, tarbuf already contains the first
1006 file block. This is a bit broken & needs fixing.
1007 **************************************************************/
1009 static int get_file(file_info2 finfo)
1011 uint16_t fnum = (uint16_t) -1;
1012 int pos = 0, dsize = 0, bpos = 0;
1013 uint64_t rsize = 0;
1014 NTSTATUS status;
1016 DEBUG(5, ("get_file: file: %s, size %.0f\n", finfo.name, (double)finfo.size));
1018 if (!ensurepath(finfo.name)) {
1019 DEBUG(0, ("abandoning restore\n"));
1020 return False;
1023 status = cli_open(cli, finfo.name, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE, &fnum);
1024 if (!NT_STATUS_IS_OK(status)) {
1025 DEBUG(0, ("abandoning restore\n"));
1026 return False;
1029 /* read the blocks from the tar file and write to the remote file */
1031 rsize = finfo.size; /* This is how much to write */
1033 while (rsize > 0) {
1035 /* We can only write up to the end of the buffer */
1036 dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, 65520); /* Calculate the size to write */
1037 dsize = MIN(dsize, rsize); /* Should be only what is left */
1038 DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos));
1040 status = cli_writeall(cli, fnum, 0,
1041 (uint8_t *)(buffer_p + bpos), pos,
1042 dsize, NULL);
1043 if (!NT_STATUS_IS_OK(status)) {
1044 DEBUG(0, ("Error writing remote file: %s\n",
1045 nt_errstr(status)));
1046 return 0;
1049 rsize -= dsize;
1050 pos += dsize;
1052 /* Now figure out how much to move in the buffer */
1054 /* FIXME, we should skip more than one block at a time */
1056 /* First, skip any initial part of the part written that is left over */
1057 /* from the end of the first TBLOCK */
1059 if ((bpos) && ((bpos + dsize) >= TBLOCK)) {
1060 dsize -= (TBLOCK - bpos); /* Get rid of the end of the first block */
1061 bpos = 0;
1063 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) { /* and skip the block */
1064 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1065 return False;
1070 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>.
1071 * If the file being extracted is an exact multiple of
1072 * TBLOCK bytes then we don't want to extract the next
1073 * block from the tarfile here, as it will be done in
1074 * the caller of get_file().
1077 while (((rsize != 0) && (dsize >= TBLOCK)) ||
1078 ((rsize == 0) && (dsize > TBLOCK))) {
1080 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1081 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1082 return False;
1085 dsize -= TBLOCK;
1087 bpos = dsize;
1090 /* Now close the file ... */
1091 status = cli_close(cli, fnum);
1092 if (!NT_STATUS_IS_OK(status)) {
1093 DEBUG(0, ("Error %s closing remote file\n",
1094 nt_errstr(status)));
1095 return(False);
1098 /* Now we update the creation date ... */
1099 DEBUG(5, ("Updating creation date on %s\n", finfo.name));
1101 if (!NT_STATUS_IS_OK(cli_setatr(cli, finfo.name, finfo.mode, finfo.mtime_ts.tv_sec))) {
1102 if (tar_real_noisy) {
1103 DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
1104 /*return(False); */ /* Ignore, as Win95 does not allow changes */
1108 ntarf++;
1109 DEBUG(0, ("restore tar file %s of size %.0f bytes\n", finfo.name, (double)finfo.size));
1110 return(True);
1113 /* Create a directory. We just ensure that the path exists and return as there
1114 is no file associated with a directory
1116 static int get_dir(file_info2 finfo)
1118 DEBUG(0, ("restore directory %s\n", finfo.name));
1120 if (!ensurepath(finfo.name)) {
1121 DEBUG(0, ("Problems creating directory\n"));
1122 return(False);
1124 ntarf++;
1125 return(True);
1128 /* Get a file with a long file name ... first file has file name, next file
1129 has the data. We only want the long file name, as the loop in do_tarput
1130 will deal with the rest.
1132 static char *get_longfilename(file_info2 finfo)
1134 /* finfo.size here is the length of the filename as written by the "/./@LongLink" name
1135 * header call. */
1136 int namesize = finfo.size + strlen(client_get_cur_dir()) + 2;
1137 char *longname = (char *)SMB_MALLOC(namesize);
1138 int offset = 0, left = finfo.size;
1139 bool first = True;
1141 DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
1142 DEBUG(5, ("Len = %.0f\n", (double)finfo.size));
1144 if (longname == NULL) {
1145 DEBUG(0, ("could not allocate buffer of size %d for longname\n", namesize));
1146 return(NULL);
1149 /* First, add cur_dir to the long file name */
1151 if (strlen(client_get_cur_dir()) > 0) {
1152 strncpy(longname, client_get_cur_dir(), namesize);
1153 offset = strlen(client_get_cur_dir());
1156 /* Loop through the blocks picking up the name */
1158 while (left > 0) {
1159 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1160 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1161 SAFE_FREE(longname);
1162 return(NULL);
1165 unfixtarname(longname + offset, buffer_p,
1166 namesize - offset, first--);
1167 DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
1169 offset += TBLOCK;
1170 left -= TBLOCK;
1173 return(longname);
1176 static void do_tarput(void)
1178 file_info2 finfo;
1179 struct timespec tp_start;
1180 char *longfilename = NULL, linkflag;
1181 int skip = False;
1183 ZERO_STRUCT(finfo);
1185 clock_gettime_mono(&tp_start);
1186 DEBUG(5, ("RJS do_tarput called ...\n"));
1188 buffer_p = tarbuf + tbufsiz; /* init this to force first read */
1190 /* Now read through those files ... */
1191 while (True) {
1192 /* Get us to the next block, or the first block first time around */
1193 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1194 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1195 SAFE_FREE(longfilename);
1196 return;
1199 DEBUG(5, ("Reading the next header ...\n"));
1201 switch (readtarheader((union hblock *) buffer_p,
1202 &finfo, client_get_cur_dir())) {
1203 case -2: /* Hmm, not good, but not fatal */
1204 DEBUG(0, ("Skipping %s...\n", finfo.name));
1205 if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) && !skip_file(finfo.size)) {
1206 DEBUG(0, ("Short file, bailing out...\n"));
1207 SAFE_FREE(longfilename);
1208 return;
1210 break;
1212 case -1:
1213 DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
1214 SAFE_FREE(longfilename);
1215 return;
1217 case 0: /* chksum is zero - looks like an EOF */
1218 DEBUG(0, ("tar: restored %d files and directories\n", ntarf));
1219 SAFE_FREE(longfilename);
1220 return; /* Hmmm, bad here ... */
1222 default:
1223 /* No action */
1224 break;
1227 /* Now, do we have a long file name? */
1228 if (longfilename != NULL) {
1229 SAFE_FREE(finfo.name); /* Free the space already allocated */
1230 finfo.name = longfilename;
1231 longfilename = NULL;
1234 /* Well, now we have a header, process the file ... */
1235 /* Should we skip the file? We have the long name as well here */
1236 skip = clipn && ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl) ||
1237 (tar_re_search && mask_match_list(finfo.name, cliplist, clipn, True)));
1239 DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
1240 if (skip) {
1241 skip_file(finfo.size);
1242 continue;
1245 /* We only get this far if we should process the file */
1246 linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
1247 switch (linkflag) {
1248 case '0': /* Should use symbolic names--FIXME */
1250 * Skip to the next block first, so we can get the file, FIXME, should
1251 * be in get_file ...
1252 * The 'finfo.size != 0' fix is from Bob Boehmer <boehmer@worldnet.att.net>
1253 * Fixes bug where file size in tarfile is zero.
1255 if ((finfo.size != 0) && next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1256 DEBUG(0, ("Short file, bailing out...\n"));
1257 return;
1259 if (!get_file(finfo)) {
1260 DEBUG(0, ("Abandoning restore\n"));
1261 return;
1263 break;
1264 case '5':
1265 if (!get_dir(finfo)) {
1266 DEBUG(0, ("Abandoning restore \n"));
1267 return;
1269 break;
1270 case 'L':
1271 SAFE_FREE(longfilename);
1272 longfilename = get_longfilename(finfo);
1273 if (!longfilename) {
1274 DEBUG(0, ("abandoning restore\n"));
1275 return;
1277 DEBUG(5, ("Long file name: %s\n", longfilename));
1278 break;
1280 default:
1281 skip_file(finfo.size); /* Don't handle these yet */
1282 break;
1288 * samba interactive commands
1291 /****************************************************************************
1292 Blocksize command
1293 ***************************************************************************/
1295 int cmd_block(void)
1297 TALLOC_CTX *ctx = talloc_tos();
1298 char *buf;
1299 int block;
1301 if (!next_token_talloc(ctx, (const char **)&cmd_ptr,&buf,NULL)) {
1302 DEBUG(0, ("blocksize <n>\n"));
1303 return 1;
1306 block=atoi(buf);
1307 if (block < 0 || block > 65535) {
1308 DEBUG(0, ("blocksize out of range"));
1309 return 1;
1312 blocksize=block;
1313 DEBUG(2,("blocksize is now %d\n", blocksize));
1314 return 0;
1317 /****************************************************************************
1318 command to set incremental / reset mode
1319 ***************************************************************************/
1321 int cmd_tarmode(void)
1323 TALLOC_CTX *ctx = talloc_tos();
1324 char *buf;
1326 while (next_token_talloc(ctx, (const char **)&cmd_ptr,&buf,NULL)) {
1327 if (strequal(buf, "full"))
1328 tar_inc=False;
1329 else if (strequal(buf, "inc"))
1330 tar_inc=True;
1331 else if (strequal(buf, "reset"))
1332 tar_reset=True;
1333 else if (strequal(buf, "noreset"))
1334 tar_reset=False;
1335 else if (strequal(buf, "system"))
1336 tar_system=True;
1337 else if (strequal(buf, "nosystem"))
1338 tar_system=False;
1339 else if (strequal(buf, "hidden"))
1340 tar_hidden=True;
1341 else if (strequal(buf, "nohidden"))
1342 tar_hidden=False;
1343 else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
1344 tar_noisy=True;
1345 else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
1346 tar_noisy=False;
1347 else
1348 DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
1349 TALLOC_FREE(buf);
1352 DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
1353 tar_inc ? "incremental" : "full",
1354 tar_system ? "system" : "nosystem",
1355 tar_hidden ? "hidden" : "nohidden",
1356 tar_reset ? "reset" : "noreset",
1357 tar_noisy ? "verbose" : "quiet"));
1358 return 0;
1361 /****************************************************************************
1362 Feeble attrib command
1363 ***************************************************************************/
1365 int cmd_setmode(void)
1367 TALLOC_CTX *ctx = talloc_tos();
1368 char *q;
1369 char *buf;
1370 char *fname = NULL;
1371 uint16 attra[2];
1372 int direct=1;
1374 attra[0] = attra[1] = 0;
1376 if (!next_token_talloc(ctx, (const char **)&cmd_ptr,&buf,NULL)) {
1377 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1378 return 1;
1381 fname = talloc_asprintf(ctx,
1382 "%s%s",
1383 client_get_cur_dir(),
1384 buf);
1385 if (!fname) {
1386 return 1;
1389 while (next_token_talloc(ctx, (const char **)&cmd_ptr,&buf,NULL)) {
1390 q=buf;
1392 while(*q) {
1393 switch (*q++) {
1394 case '+':
1395 direct=1;
1396 break;
1397 case '-':
1398 direct=0;
1399 break;
1400 case 'r':
1401 attra[direct]|=FILE_ATTRIBUTE_READONLY;
1402 break;
1403 case 'h':
1404 attra[direct]|=FILE_ATTRIBUTE_HIDDEN;
1405 break;
1406 case 's':
1407 attra[direct]|=FILE_ATTRIBUTE_SYSTEM;
1408 break;
1409 case 'a':
1410 attra[direct]|=FILE_ATTRIBUTE_ARCHIVE;
1411 break;
1412 default:
1413 DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1414 return 1;
1419 if (attra[ATTRSET]==0 && attra[ATTRRESET]==0) {
1420 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1421 return 1;
1424 DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1425 do_setrattr(fname, attra[ATTRSET], ATTRSET);
1426 do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
1427 return 0;
1431 Convert list of tokens to array; dependent on above routine.
1432 Uses the global cmd_ptr from above - bit of a hack.
1435 static char **toktocliplist(int *ctok, const char *sep)
1437 char *s=(char *)cmd_ptr;
1438 int ictok=0;
1439 char **ret, **iret;
1441 if (!sep)
1442 sep = " \t\n\r";
1444 while(*s && strchr_m(sep,*s))
1445 s++;
1447 /* nothing left? */
1448 if (!*s)
1449 return(NULL);
1451 do {
1452 ictok++;
1453 while(*s && (!strchr_m(sep,*s)))
1454 s++;
1455 while(*s && strchr_m(sep,*s))
1456 *s++=0;
1457 } while(*s);
1459 *ctok=ictok;
1460 s=(char *)cmd_ptr;
1462 if (!(ret=iret=SMB_MALLOC_ARRAY(char *,ictok+1)))
1463 return NULL;
1465 while(ictok--) {
1466 *iret++=s;
1467 if (ictok > 0) {
1468 while(*s++)
1470 while(!*s)
1471 s++;
1475 ret[*ctok] = NULL;
1476 return ret;
1479 /****************************************************************************
1480 Principal command for creating / extracting
1481 ***************************************************************************/
1483 int cmd_tar(void)
1485 TALLOC_CTX *ctx = talloc_tos();
1486 char *buf;
1487 char **argl = NULL;
1488 int argcl = 0;
1489 int ret;
1491 if (!next_token_talloc(ctx, (const char **)&cmd_ptr,&buf,NULL)) {
1492 DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
1493 return 1;
1496 argl=toktocliplist(&argcl, NULL);
1497 if (!tar_parseargs(argcl, argl, buf, 0)) {
1498 SAFE_FREE(argl);
1499 return 1;
1502 ret = process_tar();
1503 SAFE_FREE(argl);
1504 return ret;
1507 /****************************************************************************
1508 Command line (option) version
1509 ***************************************************************************/
1511 int process_tar(void)
1513 TALLOC_CTX *ctx = talloc_tos();
1514 int rc = 0;
1515 initarbuf();
1516 switch(tar_type) {
1517 case 'x':
1519 #if 0
1520 do_tarput2();
1521 #else
1522 do_tarput();
1523 #endif
1524 SAFE_FREE(tarbuf);
1525 close(tarhandle);
1526 break;
1527 case 'r':
1528 case 'c':
1529 if (clipn && tar_excl) {
1530 int i;
1531 char *tarmac = NULL;
1533 for (i=0; i<clipn; i++) {
1534 DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
1536 if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1537 *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1540 if (strrchr_m(cliplist[i], '\\')) {
1541 char *p;
1542 char saved_char;
1543 char *saved_dir = talloc_strdup(ctx,
1544 client_get_cur_dir());
1545 if (!saved_dir) {
1546 return 1;
1549 if (*cliplist[i]=='\\') {
1550 tarmac = talloc_strdup(ctx,
1551 cliplist[i]);
1552 } else {
1553 tarmac = talloc_asprintf(ctx,
1554 "%s%s",
1555 client_get_cur_dir(),
1556 cliplist[i]);
1558 if (!tarmac) {
1559 return 1;
1562 * Strip off the last \\xxx
1563 * xxx element of tarmac to set
1564 * it as current directory.
1566 p = strrchr_m(tarmac, '\\');
1567 if (!p) {
1568 return 1;
1570 saved_char = p[1];
1571 p[1] = '\0';
1573 client_set_cur_dir(tarmac);
1576 * Restore the character we
1577 * just replaced to
1578 * put the pathname
1579 * back as it was.
1581 p[1] = saved_char;
1583 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1584 do_list(tarmac,attribute,do_tar, False, True);
1586 client_set_cur_dir(saved_dir);
1588 TALLOC_FREE(saved_dir);
1589 TALLOC_FREE(tarmac);
1590 } else {
1591 tarmac = talloc_asprintf(ctx,
1592 "%s%s",
1593 client_get_cur_dir(),
1594 cliplist[i]);
1595 if (!tarmac) {
1596 return 1;
1598 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1599 do_list(tarmac,attribute,do_tar, False, True);
1600 TALLOC_FREE(tarmac);
1603 } else {
1604 char *mask = talloc_asprintf(ctx,
1605 "%s\\*",
1606 client_get_cur_dir());
1607 if (!mask) {
1608 return 1;
1610 DEBUG(5, ("process_tar, do_list with mask: %s\n", mask));
1611 do_list(mask,attribute,do_tar,False, True);
1612 TALLOC_FREE(mask);
1615 if (ntarf) {
1616 dotareof(tarhandle);
1618 close(tarhandle);
1619 SAFE_FREE(tarbuf);
1621 DEBUG(0, ("tar: dumped %d files and directories\n", ntarf));
1622 DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf));
1623 break;
1626 if (must_free_cliplist) {
1627 int i;
1628 for (i = 0; i < clipn; ++i) {
1629 SAFE_FREE(cliplist[i]);
1631 SAFE_FREE(cliplist);
1632 cliplist = NULL;
1633 clipn = 0;
1634 must_free_cliplist = False;
1636 return rc;
1639 /****************************************************************************
1640 Find a token (filename) in a clip list
1641 ***************************************************************************/
1643 static int clipfind(char **aret, int ret, char *tok)
1645 if (aret==NULL)
1646 return 0;
1648 /* ignore leading slashes or dots in token */
1649 while(strchr_m("/\\.", *tok))
1650 tok++;
1652 while(ret--) {
1653 char *pkey=*aret++;
1655 /* ignore leading slashes or dots in list */
1656 while(strchr_m("/\\.", *pkey))
1657 pkey++;
1659 if (!strslashcmp(pkey, tok))
1660 return 1;
1662 return 0;
1665 /****************************************************************************
1666 Read list of files to include from the file and initialize cliplist
1667 accordingly.
1668 ***************************************************************************/
1670 static int read_inclusion_file(char *filename)
1672 XFILE *inclusion = NULL;
1673 char buf[PATH_MAX + 1];
1674 char *inclusion_buffer = NULL;
1675 int inclusion_buffer_size = 0;
1676 int inclusion_buffer_sofar = 0;
1677 char *p;
1678 char *tmpstr;
1679 int i;
1680 int error = 0;
1682 clipn = 0;
1683 buf[PATH_MAX] = '\0'; /* guarantee null-termination */
1684 if ((inclusion = x_fopen(filename, O_RDONLY, 0)) == NULL) {
1685 /* XXX It would be better to include a reason for failure, but without
1686 * autoconf, it's hard to use strerror, sys_errlist, etc.
1688 DEBUG(0,("Unable to open inclusion file %s\n", filename));
1689 return 0;
1692 while ((! error) && (x_fgets(buf, sizeof(buf)-1, inclusion))) {
1693 if (inclusion_buffer == NULL) {
1694 inclusion_buffer_size = 1024;
1695 if ((inclusion_buffer = (char *)SMB_MALLOC(inclusion_buffer_size)) == NULL) {
1696 DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1697 error = 1;
1698 break;
1702 if (buf[strlen(buf)-1] == '\n') {
1703 buf[strlen(buf)-1] = '\0';
1706 if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1707 inclusion_buffer_size *= 2;
1708 inclusion_buffer = (char *)SMB_REALLOC(inclusion_buffer,inclusion_buffer_size);
1709 if (!inclusion_buffer) {
1710 DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1711 inclusion_buffer_size));
1712 error = 1;
1713 break;
1717 strlcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
1718 inclusion_buffer_sofar += strlen(buf) + 1;
1719 clipn++;
1721 x_fclose(inclusion);
1723 if (! error) {
1724 /* Allocate an array of clipn + 1 char*'s for cliplist */
1725 cliplist = SMB_MALLOC_ARRAY(char *, clipn + 1);
1726 if (cliplist == NULL) {
1727 DEBUG(0,("failure allocating memory for cliplist\n"));
1728 error = 1;
1729 } else {
1730 cliplist[clipn] = NULL;
1731 p = inclusion_buffer;
1732 for (i = 0; (! error) && (i < clipn); i++) {
1733 /* set current item to NULL so array will be null-terminated even if
1734 * malloc fails below. */
1735 cliplist[i] = NULL;
1736 if ((tmpstr = (char *)SMB_MALLOC(strlen(p)+1)) == NULL) {
1737 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
1738 error = 1;
1739 } else {
1740 unfixtarname(tmpstr, p, strlen(p) + 1, True);
1741 cliplist[i] = tmpstr;
1742 if ((p = strchr_m(p, '\000')) == NULL) {
1743 DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1744 abort();
1747 ++p;
1749 must_free_cliplist = True;
1753 SAFE_FREE(inclusion_buffer);
1754 if (error) {
1755 if (cliplist) {
1756 char **pp;
1757 /* We know cliplist is always null-terminated */
1758 for (pp = cliplist; *pp; ++pp) {
1759 SAFE_FREE(*pp);
1761 SAFE_FREE(cliplist);
1762 cliplist = NULL;
1763 must_free_cliplist = False;
1765 return 0;
1768 /* cliplist and its elements are freed at the end of process_tar. */
1769 return 1;
1772 /****************************************************************************
1773 Parse tar arguments. Sets tar_type, tar_excl, etc.
1774 ***************************************************************************/
1776 int tar_parseargs(int argc, char *argv[], const char *Optarg, int Optind)
1778 int newOptind = Optind;
1779 char tar_clipfl='\0';
1781 /* Reset back to defaults - could be from interactive version
1782 * reset mode and archive mode left as they are though
1784 tar_type='\0';
1785 tar_excl=True;
1786 dry_run=False;
1788 while (*Optarg) {
1789 switch(*Optarg++) {
1790 case 'c':
1791 tar_type='c';
1792 break;
1793 case 'x':
1794 if (tar_type=='c') {
1795 printf("Tar must be followed by only one of c or x.\n");
1796 return 0;
1798 tar_type='x';
1799 break;
1800 case 'b':
1801 if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1802 DEBUG(0,("Option b must be followed by valid blocksize\n"));
1803 return 0;
1804 } else {
1805 Optind++;
1806 newOptind++;
1808 break;
1809 case 'g':
1810 tar_inc=True;
1811 break;
1812 case 'N':
1813 if (Optind>=argc) {
1814 DEBUG(0,("Option N must be followed by valid file name\n"));
1815 return 0;
1816 } else {
1817 SMB_STRUCT_STAT stbuf;
1819 if (sys_stat(argv[Optind], &stbuf,
1820 false) == 0) {
1821 newer_than = convert_timespec_to_time_t(
1822 stbuf.st_ex_mtime);
1823 DEBUG(1,("Getting files newer than %s",
1824 time_to_asc(newer_than)));
1825 newOptind++;
1826 Optind++;
1827 } else {
1828 DEBUG(0,("Error setting newer-than time\n"));
1829 return 0;
1832 break;
1833 case 'a':
1834 tar_reset=True;
1835 break;
1836 case 'q':
1837 tar_noisy=False;
1838 break;
1839 case 'I':
1840 if (tar_clipfl) {
1841 DEBUG(0,("Only one of I,X,F must be specified\n"));
1842 return 0;
1844 tar_clipfl='I';
1845 break;
1846 case 'X':
1847 if (tar_clipfl) {
1848 DEBUG(0,("Only one of I,X,F must be specified\n"));
1849 return 0;
1851 tar_clipfl='X';
1852 break;
1853 case 'F':
1854 if (tar_clipfl) {
1855 DEBUG(0,("Only one of I,X,F must be specified\n"));
1856 return 0;
1858 tar_clipfl='F';
1859 break;
1860 case 'r':
1861 DEBUG(0, ("tar_re_search set\n"));
1862 tar_re_search = True;
1863 break;
1864 case 'n':
1865 if (tar_type == 'c') {
1866 DEBUG(0, ("dry_run set\n"));
1867 dry_run = True;
1868 } else {
1869 DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1870 return 0;
1872 break;
1873 default:
1874 DEBUG(0,("Unknown tar option\n"));
1875 return 0;
1879 if (!tar_type) {
1880 printf("Option T must be followed by one of c or x.\n");
1881 return 0;
1884 /* tar_excl is true if cliplist lists files to be included.
1885 * Both 'I' and 'F' mean include. */
1886 tar_excl=tar_clipfl!='X';
1888 if (tar_clipfl=='F') {
1889 if (argc-Optind-1 != 1) {
1890 DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1891 return 0;
1893 newOptind++;
1894 /* Optind points at the tar output file, Optind+1 at the inclusion file. */
1895 if (! read_inclusion_file(argv[Optind+1])) {
1896 return 0;
1898 } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
1899 char *tmpstr;
1900 char **tmplist;
1901 int clipcount;
1903 cliplist=argv+Optind+1;
1904 clipn=argc-Optind-1;
1905 clipcount = clipn;
1907 if ((tmplist=SMB_MALLOC_ARRAY(char *,clipn)) == NULL) {
1908 DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n", clipn));
1909 return 0;
1912 for (clipcount = 0; clipcount < clipn; clipcount++) {
1914 DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1916 if ((tmpstr = (char *)SMB_MALLOC(strlen(cliplist[clipcount])+1)) == NULL) {
1917 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", clipcount));
1918 SAFE_FREE(tmplist);
1919 return 0;
1922 unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
1923 tmplist[clipcount] = tmpstr;
1924 DEBUG(5, ("Processed an item, %s\n", tmpstr));
1926 DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1929 cliplist = tmplist;
1930 must_free_cliplist = True;
1932 newOptind += clipn;
1935 if (Optind+1<argc && tar_re_search && tar_clipfl != 'F') {
1936 /* Doing regular expression seaches not from an inclusion file. */
1937 clipn=argc-Optind-1;
1938 cliplist=argv+Optind+1;
1939 newOptind += clipn;
1942 if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1943 /* Sets tar handle to either 0 or 1, as appropriate */
1944 tarhandle=(tar_type=='c');
1946 * Make sure that dbf points to stderr if we are using stdout for
1947 * tar output
1949 if (tarhandle == 1) {
1950 setup_logging("smbclient", DEBUG_STDERR);
1952 if (!argv[Optind]) {
1953 DEBUG(0,("Must specify tar filename\n"));
1954 return 0;
1956 if (!strcmp(argv[Optind], "-")) {
1957 newOptind++;
1960 } else {
1961 if (tar_type=='c' && dry_run) {
1962 tarhandle=-1;
1963 } else if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1)
1964 || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0)) {
1965 DEBUG(0,("Error opening local file %s - %s\n", argv[Optind], strerror(errno)));
1966 return(0);
1968 newOptind++;
1971 return newOptind;