nss_winbind: add getgroupmembership for FreeBSD
[Samba.git] / source3 / client / clitar.c
blob7bbd6ad97552ff4ab0f5eacc214ff8c25b91d9ed
1 /*
2 Unix SMB/CIFS implementation.
3 Tar Extensions
4 Copyright (C) Ricky Poulten 1995-1998
5 Copyright (C) Richard Sharpe 1998
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 /* The following changes developed by Richard Sharpe for Canon Information
21 Systems Research Australia (CISRA)
23 1. Restore can now restore files with long file names
24 2. Save now saves directory information so that we can restore
25 directory creation times
26 3. tar now accepts both UNIX path names and DOS path names. I prefer
27 those lovely /'s to those UGLY \'s :-)
28 4. the files to exclude can be specified as a regular expression by adding
29 an r flag to the other tar flags. Eg:
31 -TcrX file.tar "*.(obj|exe)"
33 will skip all .obj and .exe files
37 #include "includes.h"
38 #include "system/filesys.h"
39 #include "clitar.h"
40 #include "client/client_proto.h"
41 #include "libsmb/libsmb.h"
43 static int clipfind(char **aret, int ret, char *tok);
45 typedef struct file_info_struct file_info2;
47 struct file_info_struct {
48 off_t size;
49 uint16 mode;
50 uid_t uid;
51 gid_t gid;
52 /* These times are normally kept in GMT */
53 struct timespec mtime_ts;
54 struct timespec atime_ts;
55 struct timespec ctime_ts;
56 char *name; /* This is dynamically allocated */
57 file_info2 *next, *prev; /* Used in the stack ... */
60 typedef struct {
61 file_info2 *top;
62 int items;
63 } stack;
65 #define SEPARATORS " \t\n\r"
66 extern time_t newer_than;
67 extern struct cli_state *cli;
69 /* These defines are for the do_setrattr routine, to indicate
70 * setting and reseting of file attributes in the function call */
71 #define ATTRSET 1
72 #define ATTRRESET 0
74 static uint16 attribute = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
77 static char *tarbuf, *buffer_p;
78 static int tp, ntarf, tbufsiz;
79 static double ttarf;
80 /* Incremental mode */
81 static bool tar_inc=False;
82 /* Reset archive bit */
83 static bool tar_reset=False;
84 /* Include / exclude mode (true=include, false=exclude) */
85 static bool tar_excl=True;
86 /* use regular expressions for search on file names */
87 static bool tar_re_search=False;
88 /* Do not dump anything, just calculate sizes */
89 static bool dry_run=False;
90 /* Dump files with System attribute */
91 static bool tar_system=True;
92 /* Dump files with Hidden attribute */
93 static bool tar_hidden=True;
94 /* Be noisy - make a catalogue */
95 static bool tar_noisy=True;
96 static bool tar_real_noisy=False; /* Don't want to be really noisy by default */
98 char tar_type='\0';
99 static char **cliplist=NULL;
100 static int clipn=0;
101 static bool must_free_cliplist = False;
102 extern char *cmd_ptr;
104 extern bool lowercase;
105 extern int get_total_time_ms;
106 extern int get_total_size;
108 static int blocksize=20;
109 static int tarhandle;
111 static void writetarheader(int f, const char *aname, uint64_t size, time_t mtime,
112 const char *amode, unsigned char ftype);
113 static NTSTATUS do_atar(const char *rname_in, char *lname,
114 struct file_info *finfo1);
115 static NTSTATUS do_tar(struct cli_state *cli_state, struct file_info *finfo,
116 const char *dir);
117 static void oct_it(uint64_t value, int ndgs, char *p);
118 static void fixtarname(char *tptr, const char *fp, size_t l);
119 static int dotarbuf(int f, char *b, int n);
120 static void dozerobuf(int f, int n);
121 static void dotareof(int f);
122 static void initarbuf(void);
124 /* restore functions */
125 static long readtarheader(union hblock *hb, file_info2 *finfo, const char *prefix);
126 static long unoct(char *p, int ndgs);
127 static void do_tarput(void);
128 static void unfixtarname(char *tptr, char *fp, int l, bool first);
131 * tar specific utitlities
134 /****************************************************************************
135 Write a tar header to buffer
136 ****************************************************************************/
138 static void writetarheader(int f, const char *aname, uint64_t size, time_t mtime,
139 const char *amode, unsigned char ftype)
141 union hblock hb;
142 int i, chk, l;
143 char *jp;
145 DEBUG(5, ("WriteTarHdr, Type = %c, Size= %.0f, Name = %s\n", ftype, (double)size, aname));
147 memset(hb.dummy, 0, sizeof(hb.dummy));
149 l=strlen(aname);
150 /* We will be prepending a '.' in fixtarheader so use +2 to
151 * take care of the . and terminating zero. JRA.
153 if (l+2 >= NAMSIZ) {
154 /* write a GNU tar style long header */
155 char *b;
156 b = (char *)SMB_MALLOC(l+TBLOCK+100);
157 if (!b) {
158 DEBUG(0,("out of memory\n"));
159 exit(1);
161 writetarheader(f, "/./@LongLink", l+2, 0, " 0 \0", 'L');
162 memset(b, 0, l+TBLOCK+100);
163 fixtarname(b, aname, l+2);
164 i = strlen(b)+1;
165 DEBUG(5, ("File name in tar file: %s, size=%d, \n", b, (int)strlen(b)));
166 dotarbuf(f, b, TBLOCK*(((i-1)/TBLOCK)+1));
167 SAFE_FREE(b);
170 fixtarname(hb.dbuf.name, aname, (l+2 >= NAMSIZ) ? NAMSIZ : l + 2);
172 if (lowercase)
173 (void)strlower_m(hb.dbuf.name);
175 /* write out a "standard" tar format header */
177 hb.dbuf.name[NAMSIZ-1]='\0';
178 strlcpy(hb.dbuf.mode, amode ? amode : "", sizeof(hb.dbuf.mode));
179 oct_it((uint64_t)0, 8, hb.dbuf.uid);
180 oct_it((uint64_t)0, 8, hb.dbuf.gid);
181 oct_it((uint64_t) size, 13, hb.dbuf.size);
182 if (size > (uint64_t)077777777777LL) {
183 /* This is a non-POSIX compatible extention to store files
184 greater than 8GB. */
186 memset(hb.dbuf.size, 0, 4);
187 hb.dbuf.size[0]=128;
188 for (i = 8; i; i--) {
189 hb.dbuf.size[i+3] = size & 0xff;
190 size >>= 8;
193 oct_it((uint64_t) mtime, 13, hb.dbuf.mtime);
194 memcpy(hb.dbuf.chksum, " ", sizeof(hb.dbuf.chksum));
195 memset(hb.dbuf.linkname, 0, NAMSIZ);
196 hb.dbuf.linkflag=ftype;
198 for (chk=0, i=sizeof(hb.dummy), jp=hb.dummy; --i>=0;)
199 chk+=(0xFF & *jp++);
201 oct_it((uint64_t) chk, 8, hb.dbuf.chksum);
202 hb.dbuf.chksum[6] = '\0';
204 (void) dotarbuf(f, hb.dummy, sizeof(hb.dummy));
207 /****************************************************************************
208 Read a tar header into a hblock structure, and validate
209 ***************************************************************************/
211 static long readtarheader(union hblock *hb, file_info2 *finfo, const char *prefix)
213 long chk, fchk;
214 int i;
215 char *jp;
218 * read in a "standard" tar format header - we're not that interested
219 * in that many fields, though
222 /* check the checksum */
223 for (chk=0, i=sizeof(hb->dummy), jp=hb->dummy; --i>=0;)
224 chk+=(0xFF & *jp++);
226 if (chk == 0)
227 return chk;
229 /* compensate for blanks in chksum header */
230 for (i=sizeof(hb->dbuf.chksum), jp=hb->dbuf.chksum; --i>=0;)
231 chk-=(0xFF & *jp++);
233 chk += ' ' * sizeof(hb->dbuf.chksum);
235 fchk=unoct(hb->dbuf.chksum, sizeof(hb->dbuf.chksum));
237 DEBUG(5, ("checksum totals chk=%ld fchk=%ld chksum=%s\n",
238 chk, fchk, hb->dbuf.chksum));
240 if (fchk != chk) {
241 DEBUG(0, ("checksums don't match %ld %ld\n", fchk, chk));
242 dump_data(5, (uint8 *)hb - TBLOCK, TBLOCK *3);
243 return -1;
246 if ((finfo->name = SMB_MALLOC(strlen(prefix) + strlen(hb -> dbuf.name) + 4)) == NULL) {
247 DEBUG(0, ("Out of space creating file_info2 for %s\n", hb -> dbuf.name));
248 return(-1);
251 strlcpy(finfo->name, prefix, strlen(prefix) + strlen(hb -> dbuf.name) + 4);
253 /* use l + 1 to do the null too; do prefix - prefcnt to zap leading slash */
254 unfixtarname(finfo->name + strlen(prefix), hb->dbuf.name,
255 strlen(hb->dbuf.name) + 1, True);
257 /* can't handle some links at present */
258 if ((hb->dbuf.linkflag != '0') && (hb -> dbuf.linkflag != '5')) {
259 if (hb->dbuf.linkflag == 0) {
260 DEBUG(6, ("Warning: NULL link flag (gnu tar archive ?) %s\n",
261 finfo->name));
262 } else {
263 if (hb -> dbuf.linkflag == 'L') { /* We have a longlink */
264 /* Do nothing here at the moment. do_tarput will handle this
265 as long as the longlink gets back to it, as it has to advance
266 the buffer pointer, etc */
267 } else {
268 DEBUG(0, ("this tar file appears to contain some kind \
269 of link other than a GNUtar Longlink - ignoring\n"));
270 return -2;
275 if ((unoct(hb->dbuf.mode, sizeof(hb->dbuf.mode)) & S_IFDIR) ||
276 (*(finfo->name+strlen(finfo->name)-1) == '\\')) {
277 finfo->mode=FILE_ATTRIBUTE_DIRECTORY;
278 } else {
279 finfo->mode=0; /* we don't care about mode at the moment, we'll
280 * just make it a regular file */
284 * Bug fix by richard@sj.co.uk
286 * REC: restore times correctly (as does tar)
287 * We only get the modification time of the file; set the creation time
288 * from the mod. time, and the access time to current time
290 finfo->mtime_ts = finfo->ctime_ts =
291 convert_time_t_to_timespec((time_t)strtol(hb->dbuf.mtime, NULL, 8));
292 finfo->atime_ts = convert_time_t_to_timespec(time(NULL));
293 if ((hb->dbuf.size[0] & 0xff) == 0x80) {
294 /* This is a non-POSIX compatible extention to extract files
295 greater than 8GB. */
296 finfo->size = 0;
297 for (i = 0; i < 8; i++) {
298 finfo->size <<= 8;
299 finfo->size |= hb->dbuf.size[i+4] & 0xff;
301 } else {
302 finfo->size = unoct(hb->dbuf.size, sizeof(hb->dbuf.size));
305 return True;
308 /****************************************************************************
309 Write out the tar buffer to tape or wherever
310 ****************************************************************************/
312 static int dotarbuf(int f, char *b, int n)
314 int fail=1, writ=n;
316 if (dry_run) {
317 return writ;
319 /* This routine and the next one should be the only ones that do write()s */
320 if (tp + n >= tbufsiz) {
321 int diff;
323 diff=tbufsiz-tp;
324 memcpy(tarbuf + tp, b, diff);
325 fail=fail && (1+sys_write(f, tarbuf, tbufsiz));
326 n-=diff;
327 b+=diff;
328 tp=0;
330 while (n >= tbufsiz) {
331 fail=fail && (1 + sys_write(f, b, tbufsiz));
332 n-=tbufsiz;
333 b+=tbufsiz;
337 if (n>0) {
338 memcpy(tarbuf+tp, b, n);
339 tp+=n;
342 return(fail ? writ : 0);
345 /****************************************************************************
346 Write zeros to buffer / tape
347 ****************************************************************************/
349 static void dozerobuf(int f, int n)
351 /* short routine just to write out n zeros to buffer -
352 * used to round files to nearest block
353 * and to do tar EOFs */
355 if (dry_run)
356 return;
358 if (n+tp >= tbufsiz) {
359 memset(tarbuf+tp, 0, tbufsiz-tp);
360 if (sys_write(f, tarbuf, tbufsiz) != tbufsiz) {
361 DEBUG(0, ("dozerobuf: sys_write fail\n"));
362 return;
364 memset(tarbuf, 0, (tp+=n-tbufsiz));
365 } else {
366 memset(tarbuf+tp, 0, n);
367 tp+=n;
371 /****************************************************************************
372 Malloc tape buffer
373 ****************************************************************************/
375 static void initarbuf(void)
377 /* initialize tar buffer */
378 tbufsiz=blocksize*TBLOCK;
379 tarbuf=(char *)SMB_MALLOC(tbufsiz); /* FIXME: We might not get the buffer */
381 /* reset tar buffer pointer and tar file counter and total dumped */
382 tp=0; ntarf=0; ttarf=0;
385 /****************************************************************************
386 Write two zero blocks at end of file
387 ****************************************************************************/
389 static void dotareof(int f)
391 SMB_STRUCT_STAT stbuf;
392 /* Two zero blocks at end of file, write out full buffer */
394 if (dry_run)
395 return;
397 (void) dozerobuf(f, TBLOCK);
398 (void) dozerobuf(f, TBLOCK);
400 if (sys_fstat(f, &stbuf, false) == -1) {
401 DEBUG(0, ("Couldn't stat file handle\n"));
402 return;
405 /* Could be a pipe, in which case S_ISREG should fail,
406 * and we should write out at full size */
407 if (tp > 0) {
408 size_t towrite = S_ISREG(stbuf.st_ex_mode) ? tp : tbufsiz;
409 if (sys_write(f, tarbuf, towrite) != towrite) {
410 DEBUG(0,("dotareof: sys_write fail\n"));
415 /****************************************************************************
416 (Un)mangle DOS pathname, make nonabsolute
417 ****************************************************************************/
419 static void fixtarname(char *tptr, const char *fp, size_t l)
421 /* add a '.' to start of file name, convert from ugly dos \'s in path
422 * to lovely unix /'s :-} */
423 *tptr++='.';
424 l--;
426 StrnCpy(tptr, fp, l-1);
427 string_replace(tptr, '\\', '/');
430 /****************************************************************************
431 Convert from decimal to octal string
432 ****************************************************************************/
434 static void oct_it (uint64_t value, int ndgs, char *p)
436 /* Converts long to octal string, pads with leading zeros */
438 /* skip final null, but do final space */
439 --ndgs;
440 p[--ndgs] = ' ';
442 /* Loop does at least one digit */
443 do {
444 p[--ndgs] = '0' + (char) (value & 7);
445 value >>= 3;
446 } while (ndgs > 0 && value != 0);
448 /* Do leading zeros */
449 while (ndgs > 0)
450 p[--ndgs] = '0';
453 /****************************************************************************
454 Convert from octal string to long
455 ***************************************************************************/
457 static long unoct(char *p, int ndgs)
459 long value=0;
460 /* Converts octal string to long, ignoring any non-digit */
462 while (--ndgs) {
463 if (isdigit((int)*p))
464 value = (value << 3) | (long) (*p - '0');
466 p++;
469 return value;
472 /****************************************************************************
473 Compare two strings in a slash insensitive way, allowing s1 to match s2
474 if s1 is an "initial" string (up to directory marker). Thus, if s2 is
475 a file in any subdirectory of s1, declare a match.
476 ***************************************************************************/
478 static int strslashcmp(char *s1, char *s2)
480 char *s1_0=s1;
482 while(*s1 && *s2 && (*s1 == *s2 || tolower_m(*s1) == tolower_m(*s2) ||
483 (*s1 == '\\' && *s2=='/') || (*s1 == '/' && *s2=='\\'))) {
484 s1++; s2++;
487 /* if s1 has a trailing slash, it compared equal, so s1 is an "initial"
488 string of s2.
490 if (!*s1 && s1 != s1_0 && (*(s1-1) == '/' || *(s1-1) == '\\'))
491 return 0;
493 /* ignore trailing slash on s1 */
494 if (!*s2 && (*s1 == '/' || *s1 == '\\') && !*(s1+1))
495 return 0;
497 /* check for s1 is an "initial" string of s2 */
498 if ((*s2 == '/' || *s2 == '\\') && !*s1)
499 return 0;
501 return *s1-*s2;
504 /****************************************************************************
505 Ensure a remote path exists (make if necessary)
506 ***************************************************************************/
508 static bool ensurepath(const char *fname)
510 /* *must* be called with buffer ready malloc'ed */
511 /* ensures path exists */
513 char *partpath, *ffname;
514 size_t fnamelen = strlen(fname)+1;
515 const char *p=fname;
516 char *basehack;
517 char *saveptr;
518 NTSTATUS status;
520 DEBUG(5, ( "Ensurepath called with: %s\n", fname));
522 partpath = SMB_MALLOC(fnamelen);
523 ffname = SMB_MALLOC(fnamelen);
525 if ((partpath == NULL) || (ffname == NULL)){
526 DEBUG(0, ("Out of memory in ensurepath: %s\n", fname));
527 SAFE_FREE(partpath);
528 SAFE_FREE(ffname);
529 return(False);
532 *partpath = 0;
534 /* fname copied to ffname so can strtok_r */
536 strlcpy(ffname, fname, fnamelen);
538 /* do a `basename' on ffname, so don't try and make file name directory */
539 if ((basehack=strrchr_m(ffname, '\\')) == NULL) {
540 SAFE_FREE(partpath);
541 SAFE_FREE(ffname);
542 return True;
543 } else {
544 *basehack='\0';
547 p=strtok_r(ffname, "\\", &saveptr);
549 while (p) {
550 strlcat(partpath, p, fnamelen);
552 status = cli_chkpath(cli, partpath);
553 if (!NT_STATUS_IS_OK(status)) {
554 status = cli_mkdir(cli, partpath);
555 if (!NT_STATUS_IS_OK(status)) {
556 SAFE_FREE(partpath);
557 SAFE_FREE(ffname);
558 DEBUG(0, ("Error mkdir %s\n", nt_errstr(status)));
559 return False;
560 } else {
561 DEBUG(3, ("mkdirhiering %s\n", partpath));
565 strlcat(partpath, "\\", fnamelen);
566 p = strtok_r(NULL, "/\\", &saveptr);
569 SAFE_FREE(partpath);
570 SAFE_FREE(ffname);
571 return True;
574 static int padit(char *buf, uint64_t bufsize, uint64_t padsize)
576 int berr= 0;
577 int bytestowrite;
579 DEBUG(5, ("Padding with %0.f zeros\n", (double)padsize));
580 memset(buf, 0, (size_t)bufsize);
581 while( !berr && padsize > 0 ) {
582 bytestowrite= (int)MIN(bufsize, padsize);
583 berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite;
584 padsize -= bytestowrite;
587 return berr;
590 static void do_setrattr(char *name, uint16 attr, int set)
592 uint16 oldattr;
593 NTSTATUS status;
595 if (!NT_STATUS_IS_OK(cli_getatr(cli, name, &oldattr, NULL, NULL))) {
596 return;
599 if (set == ATTRSET) {
600 attr |= oldattr;
601 } else {
602 attr = oldattr & ~attr;
605 status = cli_setatr(cli, name, attr, 0);
606 if (!NT_STATUS_IS_OK(status)) {
607 DEBUG(1, ("setatr failed: %s\n", nt_errstr(status)));
611 /****************************************************************************
612 append one remote file to the tar file
613 ***************************************************************************/
615 static NTSTATUS do_atar(const char *rname_in, char *lname,
616 struct file_info *finfo1)
618 uint16_t fnum = (uint16_t)-1;
619 uint64_t nread=0;
620 char ftype;
621 file_info2 finfo;
622 bool shallitime=True;
623 char *data = NULL;
624 int read_size = 65520;
625 size_t datalen=0;
626 char *rname = NULL;
627 TALLOC_CTX *ctx = talloc_stackframe();
628 NTSTATUS status = NT_STATUS_OK;
629 struct timespec tp_start;
631 clock_gettime_mono(&tp_start);
633 data = SMB_MALLOC_ARRAY(char, read_size);
634 if (!data) {
635 DEBUG(0,("do_atar: out of memory.\n"));
636 status = NT_STATUS_NO_MEMORY;
637 goto cleanup;
640 ftype = '0'; /* An ordinary file ... */
642 ZERO_STRUCT(finfo);
644 finfo.size = finfo1 -> size;
645 finfo.mode = finfo1 -> mode;
646 finfo.uid = finfo1 -> uid;
647 finfo.gid = finfo1 -> gid;
648 finfo.mtime_ts = finfo1 -> mtime_ts;
649 finfo.atime_ts = finfo1 -> atime_ts;
650 finfo.ctime_ts = finfo1 -> ctime_ts;
652 if (dry_run) {
653 DEBUG(3,("skipping file %s of size %12.0f bytes\n", finfo1->name,
654 (double)finfo.size));
655 shallitime=0;
656 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
657 ntarf++;
658 goto cleanup;
661 rname = clean_name(ctx, rname_in);
662 if (!rname) {
663 status = NT_STATUS_NO_MEMORY;
664 goto cleanup;
667 status = cli_open(cli, rname, O_RDONLY, DENY_NONE, &fnum);
668 if (!NT_STATUS_IS_OK(status)) {
669 DEBUG(0,("%s opening remote file %s (%s)\n",
670 nt_errstr(status),rname, client_get_cur_dir()));
671 goto cleanup;
674 finfo.name = smb_xstrdup(rname);
675 if (finfo.name == NULL) {
676 DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n"));
677 status = NT_STATUS_NO_MEMORY;
678 goto cleanup;
681 DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
683 if (tar_inc && !(finfo.mode & FILE_ATTRIBUTE_ARCHIVE)) {
684 DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
685 shallitime=0;
686 } else if (!tar_system && (finfo.mode & FILE_ATTRIBUTE_SYSTEM)) {
687 DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
688 shallitime=0;
689 } else if (!tar_hidden && (finfo.mode & FILE_ATTRIBUTE_HIDDEN)) {
690 DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
691 shallitime=0;
692 } else {
693 bool wrote_tar_header = False;
695 DEBUG(3,("getting file %s of size %.0f bytes as a tar file %s",
696 finfo.name, (double)finfo.size, lname));
698 do {
700 DEBUG(3,("nread=%.0f\n",(double)nread));
702 status = cli_read(cli, fnum, data, nread,
703 read_size, &datalen);
704 if (!NT_STATUS_IS_OK(status)) {
705 DEBUG(0,("Error reading file %s : %s\n",
706 rname, nt_errstr(status)));
707 break;
710 nread += datalen;
712 /* Only if the first read succeeds, write out the tar header. */
713 if (!wrote_tar_header) {
714 /* write a tar header, don't bother with mode - just set to 100644 */
715 writetarheader(tarhandle, rname, finfo.size,
716 finfo.mtime_ts.tv_sec, "100644 \0", ftype);
717 wrote_tar_header = True;
720 /* if file size has increased since we made file size query, truncate
721 read so tar header for this file will be correct.
724 if (nread > finfo.size) {
725 datalen -= nread - finfo.size;
726 DEBUG(0,("File size change - truncating %s to %.0f bytes\n",
727 finfo.name, (double)finfo.size));
730 /* add received bits of file to buffer - dotarbuf will
731 * write out in 512 byte intervals */
733 if (dotarbuf(tarhandle,data,datalen) != datalen) {
734 DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
735 status = map_nt_error_from_unix(errno);
736 break;
739 if ( (datalen == 0) && (finfo.size != 0) ) {
740 status = NT_STATUS_UNSUCCESSFUL;
741 DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
742 break;
745 datalen=0;
746 } while ( nread < finfo.size );
748 if (wrote_tar_header) {
749 /* pad tar file with zero's if we couldn't get entire file */
750 if (nread < finfo.size) {
751 DEBUG(0, ("Didn't get entire file. size=%.0f, nread=%d\n",
752 (double)finfo.size, (int)nread));
753 if (padit(data, (uint64_t)sizeof(data), finfo.size - nread)) {
754 status = map_nt_error_from_unix(errno);
755 DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
759 /* round tar file to nearest block */
760 if (finfo.size % TBLOCK)
761 dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
763 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
764 ntarf++;
765 } else {
766 DEBUG(4, ("skipping %s - initial read failed (file was locked ?)\n", finfo.name));
767 shallitime=0;
768 status = NT_STATUS_UNSUCCESSFUL;
772 cli_close(cli, fnum);
773 fnum = -1;
775 if (shallitime) {
776 struct timespec tp_end;
777 int this_time;
779 /* if shallitime is true then we didn't skip */
780 if (tar_reset && !dry_run)
781 (void) do_setrattr(finfo.name, FILE_ATTRIBUTE_ARCHIVE, ATTRRESET);
783 clock_gettime_mono(&tp_end);
784 this_time = (tp_end.tv_sec - tp_start.tv_sec)*1000 + (tp_end.tv_nsec - tp_start.tv_nsec)/1000000;
785 get_total_time_ms += this_time;
786 get_total_size += finfo.size;
788 if (tar_noisy) {
789 DEBUG(0, ("%12.0f (%7.1f kb/s) %s\n",
790 (double)finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
791 finfo.name));
794 /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
795 DEBUG(3,("(%g kb/s) (average %g kb/s)\n",
796 finfo.size / MAX(0.001, (1.024*this_time)),
797 get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
800 cleanup:
802 if (fnum != (uint16_t)-1) {
803 cli_close(cli, fnum);
804 fnum = -1;
806 TALLOC_FREE(ctx);
807 SAFE_FREE(data);
808 return status;
811 /****************************************************************************
812 Append single file to tar file (or not)
813 ***************************************************************************/
815 static NTSTATUS do_tar(struct cli_state *cli_state, struct file_info *finfo,
816 const char *dir)
818 TALLOC_CTX *ctx = talloc_stackframe();
819 NTSTATUS status = NT_STATUS_OK;
821 if (strequal(finfo->name,"..") || strequal(finfo->name,".")) {
822 status = NT_STATUS_OK;
823 goto cleanup;
826 /* Is it on the exclude list ? */
827 if (!tar_excl && clipn) {
828 char *exclaim;
830 DEBUG(5, ("Excl: strlen(cur_dir) = %d\n", (int)strlen(client_get_cur_dir())));
832 exclaim = talloc_asprintf(ctx,
833 "%s\\%s",
834 client_get_cur_dir(),
835 finfo->name);
836 if (!exclaim) {
837 status = NT_STATUS_NO_MEMORY;
838 goto cleanup;
841 DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
843 if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
844 (tar_re_search && mask_match_list(exclaim, cliplist, clipn, True))) {
845 DEBUG(3,("Skipping file %s\n", exclaim));
846 TALLOC_FREE(exclaim);
847 status = NT_STATUS_OK;
848 goto cleanup;
850 TALLOC_FREE(exclaim);
853 if (finfo->mode & FILE_ATTRIBUTE_DIRECTORY) {
854 char *saved_curdir = NULL;
855 char *new_cd = NULL;
856 char *mtar_mask = NULL;
858 saved_curdir = talloc_strdup(ctx, client_get_cur_dir());
859 if (!saved_curdir) {
860 status = NT_STATUS_NO_MEMORY;
861 goto cleanup;
864 DEBUG(5, ("strlen(cur_dir)=%d, \
865 strlen(finfo->name)=%d\nname=%s,cur_dir=%s\n",
866 (int)strlen(saved_curdir),
867 (int)strlen(finfo->name), finfo->name, saved_curdir));
869 new_cd = talloc_asprintf(ctx,
870 "%s%s\\",
871 client_get_cur_dir(),
872 finfo->name);
873 if (!new_cd) {
874 status = NT_STATUS_NO_MEMORY;
875 goto cleanup;
877 client_set_cur_dir(new_cd);
879 DEBUG(5, ("Writing a dir, Name = %s\n", client_get_cur_dir()));
881 /* write a tar directory, don't bother with mode - just
882 * set it to 40755 */
883 writetarheader(tarhandle, client_get_cur_dir(), 0,
884 finfo->mtime_ts.tv_sec, "040755 \0", '5');
885 if (tar_noisy) {
886 DEBUG(0,(" directory %s\n",
887 client_get_cur_dir()));
889 ntarf++; /* Make sure we have a file on there */
890 mtar_mask = talloc_asprintf(ctx,
891 "%s*",
892 client_get_cur_dir());
893 if (!mtar_mask) {
894 status = NT_STATUS_NO_MEMORY;
895 goto cleanup;
897 DEBUG(5, ("Doing list with mtar_mask: %s\n", mtar_mask));
898 do_list(mtar_mask, attribute, do_tar, False, True);
899 client_set_cur_dir(saved_curdir);
900 TALLOC_FREE(saved_curdir);
901 TALLOC_FREE(new_cd);
902 TALLOC_FREE(mtar_mask);
903 } else {
904 char *rname = talloc_asprintf(ctx,
905 "%s%s",
906 client_get_cur_dir(),
907 finfo->name);
908 if (!rname) {
909 status = NT_STATUS_NO_MEMORY;
910 goto cleanup;
912 status = do_atar(rname,finfo->name,finfo);
913 TALLOC_FREE(rname);
916 cleanup:
917 TALLOC_FREE(ctx);
918 return status;
921 /****************************************************************************
922 Convert from UNIX to DOS file names
923 ***************************************************************************/
925 static void unfixtarname(char *tptr, char *fp, int l, bool first)
927 /* remove '.' from start of file name, convert from unix /'s to
928 * dos \'s in path. Kill any absolute path names. But only if first!
931 DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
933 if (first) {
934 if (*fp == '.') {
935 fp++;
936 l--;
938 if (*fp == '\\' || *fp == '/') {
939 fp++;
940 l--;
942 if (l <= 0) {
943 return;
947 strlcpy(tptr, fp, l);
948 string_replace(tptr, '/', '\\');
951 /****************************************************************************
952 Move to the next block in the buffer, which may mean read in another set of
953 blocks. FIXME, we should allow more than one block to be skipped.
954 ****************************************************************************/
956 static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
958 int bufread, total = 0;
960 DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp));
961 *bufferp += TBLOCK;
962 total = TBLOCK;
964 if (*bufferp >= (ltarbuf + bufsiz)) {
966 DEBUG(5, ("Reading more data into ltarbuf ...\n"));
969 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>
970 * Fixes bug where read can return short if coming from
971 * a pipe.
974 bufread = read(tarhandle, ltarbuf, bufsiz);
975 total = bufread;
977 while (total < bufsiz) {
978 if (bufread < 0) { /* An error, return false */
979 return (total > 0 ? -2 : bufread);
981 if (bufread == 0) {
982 if (total <= 0) {
983 return -2;
985 break;
987 bufread = read(tarhandle, &ltarbuf[total], bufsiz - total);
988 total += bufread;
991 DEBUG(5, ("Total bytes read ... %i\n", total));
993 *bufferp = ltarbuf;
996 return(total);
999 /* Skip a file, even if it includes a long file name? */
1000 static int skip_file(int skipsize)
1002 int dsize = skipsize;
1004 DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
1006 /* FIXME, we should skip more than one block at a time */
1008 while (dsize > 0) {
1009 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1010 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1011 return(False);
1013 dsize -= TBLOCK;
1016 return(True);
1019 /*************************************************************
1020 Get a file from the tar file and store it.
1021 When this is called, tarbuf already contains the first
1022 file block. This is a bit broken & needs fixing.
1023 **************************************************************/
1025 static int get_file(file_info2 finfo)
1027 uint16_t fnum = (uint16_t) -1;
1028 int dsize = 0, bpos = 0;
1029 uint64_t rsize = 0, pos = 0;
1030 NTSTATUS status;
1032 DEBUG(5, ("get_file: file: %s, size %.0f\n", finfo.name, (double)finfo.size));
1034 if (!ensurepath(finfo.name)) {
1035 DEBUG(0, ("abandoning restore\n"));
1036 return False;
1039 status = cli_open(cli, finfo.name, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE, &fnum);
1040 if (!NT_STATUS_IS_OK(status)) {
1041 DEBUG(0, ("abandoning restore\n"));
1042 return False;
1045 /* read the blocks from the tar file and write to the remote file */
1047 rsize = finfo.size; /* This is how much to write */
1049 while (rsize > 0) {
1051 /* We can only write up to the end of the buffer */
1052 dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, 65520); /* Calculate the size to write */
1053 dsize = MIN(dsize, rsize); /* Should be only what is left */
1054 DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos));
1056 status = cli_writeall(cli, fnum, 0,
1057 (uint8_t *)(buffer_p + bpos), pos,
1058 dsize, NULL);
1059 if (!NT_STATUS_IS_OK(status)) {
1060 DEBUG(0, ("Error writing remote file: %s\n",
1061 nt_errstr(status)));
1062 return 0;
1065 rsize -= dsize;
1066 pos += dsize;
1068 /* Now figure out how much to move in the buffer */
1070 /* FIXME, we should skip more than one block at a time */
1072 /* First, skip any initial part of the part written that is left over */
1073 /* from the end of the first TBLOCK */
1075 if ((bpos) && ((bpos + dsize) >= TBLOCK)) {
1076 dsize -= (TBLOCK - bpos); /* Get rid of the end of the first block */
1077 bpos = 0;
1079 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) { /* and skip the block */
1080 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1081 return False;
1086 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>.
1087 * If the file being extracted is an exact multiple of
1088 * TBLOCK bytes then we don't want to extract the next
1089 * block from the tarfile here, as it will be done in
1090 * the caller of get_file().
1093 while (((rsize != 0) && (dsize >= TBLOCK)) ||
1094 ((rsize == 0) && (dsize > TBLOCK))) {
1096 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1097 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1098 return False;
1101 dsize -= TBLOCK;
1103 bpos = dsize;
1106 /* Now close the file ... */
1107 status = cli_close(cli, fnum);
1108 if (!NT_STATUS_IS_OK(status)) {
1109 DEBUG(0, ("Error %s closing remote file\n",
1110 nt_errstr(status)));
1111 return(False);
1114 /* Now we update the creation date ... */
1115 DEBUG(5, ("Updating creation date on %s\n", finfo.name));
1117 if (!NT_STATUS_IS_OK(cli_setatr(cli, finfo.name, finfo.mode, finfo.mtime_ts.tv_sec))) {
1118 if (tar_real_noisy) {
1119 DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
1120 /*return(False); */ /* Ignore, as Win95 does not allow changes */
1124 ntarf++;
1125 DEBUG(0, ("restore tar file %s of size %.0f bytes\n", finfo.name, (double)finfo.size));
1126 return(True);
1129 /* Create a directory. We just ensure that the path exists and return as there
1130 is no file associated with a directory
1132 static int get_dir(file_info2 finfo)
1134 DEBUG(0, ("restore directory %s\n", finfo.name));
1136 if (!ensurepath(finfo.name)) {
1137 DEBUG(0, ("Problems creating directory\n"));
1138 return(False);
1140 ntarf++;
1141 return(True);
1144 /* Get a file with a long file name ... first file has file name, next file
1145 has the data. We only want the long file name, as the loop in do_tarput
1146 will deal with the rest.
1148 static char *get_longfilename(file_info2 finfo)
1150 /* finfo.size here is the length of the filename as written by the "/./@LongLink" name
1151 * header call. */
1152 int namesize = finfo.size + strlen(client_get_cur_dir()) + 2;
1153 char *longname = (char *)SMB_MALLOC(namesize);
1154 int offset = 0, left = finfo.size;
1155 bool first = True;
1157 DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
1158 DEBUG(5, ("Len = %.0f\n", (double)finfo.size));
1160 if (longname == NULL) {
1161 DEBUG(0, ("could not allocate buffer of size %d for longname\n", namesize));
1162 return(NULL);
1165 /* First, add cur_dir to the long file name */
1167 if (strlen(client_get_cur_dir()) > 0) {
1168 strncpy(longname, client_get_cur_dir(), namesize);
1169 offset = strlen(client_get_cur_dir());
1172 /* Loop through the blocks picking up the name */
1174 while (left > 0) {
1175 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1176 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1177 SAFE_FREE(longname);
1178 return(NULL);
1181 unfixtarname(longname + offset, buffer_p,
1182 namesize - offset, first--);
1183 DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
1185 offset += TBLOCK;
1186 left -= TBLOCK;
1189 return(longname);
1192 static void do_tarput(void)
1194 file_info2 finfo;
1195 struct timespec tp_start;
1196 char *longfilename = NULL, linkflag;
1197 int skip = False;
1199 ZERO_STRUCT(finfo);
1201 clock_gettime_mono(&tp_start);
1202 DEBUG(5, ("RJS do_tarput called ...\n"));
1204 buffer_p = tarbuf + tbufsiz; /* init this to force first read */
1206 /* Now read through those files ... */
1207 while (True) {
1208 /* Get us to the next block, or the first block first time around */
1209 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1210 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1211 SAFE_FREE(longfilename);
1212 return;
1215 DEBUG(5, ("Reading the next header ...\n"));
1217 switch (readtarheader((union hblock *) buffer_p,
1218 &finfo, client_get_cur_dir())) {
1219 case -2: /* Hmm, not good, but not fatal */
1220 DEBUG(0, ("Skipping %s...\n", finfo.name));
1221 if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) && !skip_file(finfo.size)) {
1222 DEBUG(0, ("Short file, bailing out...\n"));
1223 SAFE_FREE(longfilename);
1224 return;
1226 break;
1228 case -1:
1229 DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
1230 SAFE_FREE(longfilename);
1231 return;
1233 case 0: /* chksum is zero - looks like an EOF */
1234 DEBUG(0, ("tar: restored %d files and directories\n", ntarf));
1235 SAFE_FREE(longfilename);
1236 return; /* Hmmm, bad here ... */
1238 default:
1239 /* No action */
1240 break;
1243 /* Now, do we have a long file name? */
1244 if (longfilename != NULL) {
1245 SAFE_FREE(finfo.name); /* Free the space already allocated */
1246 finfo.name = longfilename;
1247 longfilename = NULL;
1250 /* Well, now we have a header, process the file ... */
1251 /* Should we skip the file? We have the long name as well here */
1252 skip = clipn && ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl) ||
1253 (tar_re_search && mask_match_list(finfo.name, cliplist, clipn, True)));
1255 DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
1256 if (skip) {
1257 skip_file(finfo.size);
1258 continue;
1261 /* We only get this far if we should process the file */
1262 linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
1263 switch (linkflag) {
1264 case '0': /* Should use symbolic names--FIXME */
1266 * Skip to the next block first, so we can get the file, FIXME, should
1267 * be in get_file ...
1268 * The 'finfo.size != 0' fix is from Bob Boehmer <boehmer@worldnet.att.net>
1269 * Fixes bug where file size in tarfile is zero.
1271 if ((finfo.size != 0) && next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1272 DEBUG(0, ("Short file, bailing out...\n"));
1273 return;
1275 if (!get_file(finfo)) {
1276 DEBUG(0, ("Abandoning restore\n"));
1277 return;
1279 break;
1280 case '5':
1281 if (!get_dir(finfo)) {
1282 DEBUG(0, ("Abandoning restore \n"));
1283 return;
1285 break;
1286 case 'L':
1287 SAFE_FREE(longfilename);
1288 longfilename = get_longfilename(finfo);
1289 if (!longfilename) {
1290 DEBUG(0, ("abandoning restore\n"));
1291 return;
1293 DEBUG(5, ("Long file name: %s\n", longfilename));
1294 break;
1296 default:
1297 skip_file(finfo.size); /* Don't handle these yet */
1298 break;
1304 * samba interactive commands
1307 /****************************************************************************
1308 Blocksize command
1309 ***************************************************************************/
1311 int cmd_block(void)
1313 TALLOC_CTX *ctx = talloc_tos();
1314 char *buf;
1315 int block;
1317 if (!next_token_talloc(ctx, (const char **)&cmd_ptr,&buf,NULL)) {
1318 DEBUG(0, ("blocksize <n>\n"));
1319 return 1;
1322 block=atoi(buf);
1323 if (block < 0 || block > 65535) {
1324 DEBUG(0, ("blocksize out of range"));
1325 return 1;
1328 blocksize=block;
1329 DEBUG(2,("blocksize is now %d\n", blocksize));
1330 return 0;
1333 /****************************************************************************
1334 command to set incremental / reset mode
1335 ***************************************************************************/
1337 int cmd_tarmode(void)
1339 TALLOC_CTX *ctx = talloc_tos();
1340 char *buf;
1342 while (next_token_talloc(ctx, (const char **)&cmd_ptr,&buf,NULL)) {
1343 if (strequal(buf, "full"))
1344 tar_inc=False;
1345 else if (strequal(buf, "inc"))
1346 tar_inc=True;
1347 else if (strequal(buf, "reset"))
1348 tar_reset=True;
1349 else if (strequal(buf, "noreset"))
1350 tar_reset=False;
1351 else if (strequal(buf, "system"))
1352 tar_system=True;
1353 else if (strequal(buf, "nosystem"))
1354 tar_system=False;
1355 else if (strequal(buf, "hidden"))
1356 tar_hidden=True;
1357 else if (strequal(buf, "nohidden"))
1358 tar_hidden=False;
1359 else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
1360 tar_noisy=True;
1361 else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
1362 tar_noisy=False;
1363 else
1364 DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
1365 TALLOC_FREE(buf);
1368 DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
1369 tar_inc ? "incremental" : "full",
1370 tar_system ? "system" : "nosystem",
1371 tar_hidden ? "hidden" : "nohidden",
1372 tar_reset ? "reset" : "noreset",
1373 tar_noisy ? "verbose" : "quiet"));
1374 return 0;
1377 /****************************************************************************
1378 Feeble attrib command
1379 ***************************************************************************/
1381 int cmd_setmode(void)
1383 TALLOC_CTX *ctx = talloc_tos();
1384 char *q;
1385 char *buf;
1386 char *fname = NULL;
1387 uint16 attra[2];
1388 int direct=1;
1390 attra[0] = attra[1] = 0;
1392 if (!next_token_talloc(ctx, (const char **)&cmd_ptr,&buf,NULL)) {
1393 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1394 return 1;
1397 fname = talloc_asprintf(ctx,
1398 "%s%s",
1399 client_get_cur_dir(),
1400 buf);
1401 if (!fname) {
1402 return 1;
1405 while (next_token_talloc(ctx, (const char **)&cmd_ptr,&buf,NULL)) {
1406 q=buf;
1408 while(*q) {
1409 switch (*q++) {
1410 case '+':
1411 direct=1;
1412 break;
1413 case '-':
1414 direct=0;
1415 break;
1416 case 'r':
1417 attra[direct]|=FILE_ATTRIBUTE_READONLY;
1418 break;
1419 case 'h':
1420 attra[direct]|=FILE_ATTRIBUTE_HIDDEN;
1421 break;
1422 case 's':
1423 attra[direct]|=FILE_ATTRIBUTE_SYSTEM;
1424 break;
1425 case 'a':
1426 attra[direct]|=FILE_ATTRIBUTE_ARCHIVE;
1427 break;
1428 default:
1429 DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1430 return 1;
1435 if (attra[ATTRSET]==0 && attra[ATTRRESET]==0) {
1436 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1437 return 1;
1440 DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1441 do_setrattr(fname, attra[ATTRSET], ATTRSET);
1442 do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
1443 return 0;
1447 Convert list of tokens to array; dependent on above routine.
1448 Uses the global cmd_ptr from above - bit of a hack.
1451 static char **toktocliplist(int *ctok, const char *sep)
1453 char *s=(char *)cmd_ptr;
1454 int ictok=0;
1455 char **ret, **iret;
1457 if (!sep)
1458 sep = " \t\n\r";
1460 while(*s && strchr_m(sep,*s))
1461 s++;
1463 /* nothing left? */
1464 if (!*s)
1465 return(NULL);
1467 do {
1468 ictok++;
1469 while(*s && (!strchr_m(sep,*s)))
1470 s++;
1471 while(*s && strchr_m(sep,*s))
1472 *s++=0;
1473 } while(*s);
1475 *ctok=ictok;
1476 s=(char *)cmd_ptr;
1478 if (!(ret=iret=SMB_MALLOC_ARRAY(char *,ictok+1)))
1479 return NULL;
1481 while(ictok--) {
1482 *iret++=s;
1483 if (ictok > 0) {
1484 while(*s++)
1486 while(!*s)
1487 s++;
1491 ret[*ctok] = NULL;
1492 return ret;
1495 /****************************************************************************
1496 Principal command for creating / extracting
1497 ***************************************************************************/
1499 int cmd_tar(void)
1501 TALLOC_CTX *ctx = talloc_tos();
1502 char *buf;
1503 char **argl = NULL;
1504 int argcl = 0;
1505 int ret;
1507 if (!next_token_talloc(ctx, (const char **)&cmd_ptr,&buf,NULL)) {
1508 DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
1509 return 1;
1512 argl=toktocliplist(&argcl, NULL);
1513 if (!tar_parseargs(argcl, argl, buf, 0)) {
1514 SAFE_FREE(argl);
1515 return 1;
1518 ret = process_tar();
1519 SAFE_FREE(argl);
1520 return ret;
1523 /****************************************************************************
1524 Command line (option) version
1525 ***************************************************************************/
1527 int process_tar(void)
1529 TALLOC_CTX *ctx = talloc_tos();
1530 int rc = 0;
1531 initarbuf();
1532 switch(tar_type) {
1533 case 'x':
1535 #if 0
1536 do_tarput2();
1537 #else
1538 do_tarput();
1539 #endif
1540 SAFE_FREE(tarbuf);
1541 close(tarhandle);
1542 break;
1543 case 'r':
1544 case 'c':
1545 if (clipn && tar_excl) {
1546 int i;
1547 char *tarmac = NULL;
1549 for (i=0; i<clipn; i++) {
1550 DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
1552 if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1553 *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1556 if (strrchr_m(cliplist[i], '\\')) {
1557 char *p;
1558 char saved_char;
1559 char *saved_dir = talloc_strdup(ctx,
1560 client_get_cur_dir());
1561 if (!saved_dir) {
1562 return 1;
1565 if (*cliplist[i]=='\\') {
1566 tarmac = talloc_strdup(ctx,
1567 cliplist[i]);
1568 } else {
1569 tarmac = talloc_asprintf(ctx,
1570 "%s%s",
1571 client_get_cur_dir(),
1572 cliplist[i]);
1574 if (!tarmac) {
1575 return 1;
1578 * Strip off the last \\xxx
1579 * xxx element of tarmac to set
1580 * it as current directory.
1582 p = strrchr_m(tarmac, '\\');
1583 if (!p) {
1584 return 1;
1586 saved_char = p[1];
1587 p[1] = '\0';
1589 client_set_cur_dir(tarmac);
1592 * Restore the character we
1593 * just replaced to
1594 * put the pathname
1595 * back as it was.
1597 p[1] = saved_char;
1599 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1600 do_list(tarmac,attribute,do_tar, False, True);
1602 client_set_cur_dir(saved_dir);
1604 TALLOC_FREE(saved_dir);
1605 TALLOC_FREE(tarmac);
1606 } else {
1607 tarmac = talloc_asprintf(ctx,
1608 "%s%s",
1609 client_get_cur_dir(),
1610 cliplist[i]);
1611 if (!tarmac) {
1612 return 1;
1614 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1615 do_list(tarmac,attribute,do_tar, False, True);
1616 TALLOC_FREE(tarmac);
1619 } else {
1620 char *mask = talloc_asprintf(ctx,
1621 "%s\\*",
1622 client_get_cur_dir());
1623 if (!mask) {
1624 return 1;
1626 DEBUG(5, ("process_tar, do_list with mask: %s\n", mask));
1627 do_list(mask,attribute,do_tar,False, True);
1628 TALLOC_FREE(mask);
1631 if (ntarf) {
1632 dotareof(tarhandle);
1634 close(tarhandle);
1635 SAFE_FREE(tarbuf);
1637 DEBUG(0, ("tar: dumped %d files and directories\n", ntarf));
1638 DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf));
1639 break;
1642 if (must_free_cliplist) {
1643 int i;
1644 for (i = 0; i < clipn; ++i) {
1645 SAFE_FREE(cliplist[i]);
1647 SAFE_FREE(cliplist);
1648 cliplist = NULL;
1649 clipn = 0;
1650 must_free_cliplist = False;
1652 return rc;
1655 /****************************************************************************
1656 Find a token (filename) in a clip list
1657 ***************************************************************************/
1659 static int clipfind(char **aret, int ret, char *tok)
1661 if (aret==NULL)
1662 return 0;
1664 /* ignore leading slashes or dots in token */
1665 while(strchr_m("/\\.", *tok))
1666 tok++;
1668 while(ret--) {
1669 char *pkey=*aret++;
1671 /* ignore leading slashes or dots in list */
1672 while(strchr_m("/\\.", *pkey))
1673 pkey++;
1675 if (!strslashcmp(pkey, tok))
1676 return 1;
1678 return 0;
1681 /****************************************************************************
1682 Read list of files to include from the file and initialize cliplist
1683 accordingly.
1684 ***************************************************************************/
1686 static int read_inclusion_file(char *filename)
1688 XFILE *inclusion = NULL;
1689 char buf[PATH_MAX + 1];
1690 char *inclusion_buffer = NULL;
1691 int inclusion_buffer_size = 0;
1692 int inclusion_buffer_sofar = 0;
1693 char *p;
1694 char *tmpstr;
1695 int i;
1696 int error = 0;
1698 clipn = 0;
1699 buf[PATH_MAX] = '\0'; /* guarantee null-termination */
1700 if ((inclusion = x_fopen(filename, O_RDONLY, 0)) == NULL) {
1701 /* XXX It would be better to include a reason for failure, but without
1702 * autoconf, it's hard to use strerror, sys_errlist, etc.
1704 DEBUG(0,("Unable to open inclusion file %s\n", filename));
1705 return 0;
1708 while ((! error) && (x_fgets(buf, sizeof(buf)-1, inclusion))) {
1709 if (inclusion_buffer == NULL) {
1710 inclusion_buffer_size = 1024;
1711 if ((inclusion_buffer = (char *)SMB_MALLOC(inclusion_buffer_size)) == NULL) {
1712 DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1713 error = 1;
1714 break;
1718 if (buf[strlen(buf)-1] == '\n') {
1719 buf[strlen(buf)-1] = '\0';
1722 if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1723 inclusion_buffer_size *= 2;
1724 inclusion_buffer = (char *)SMB_REALLOC(inclusion_buffer,inclusion_buffer_size);
1725 if (!inclusion_buffer) {
1726 DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1727 inclusion_buffer_size));
1728 error = 1;
1729 break;
1733 strlcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
1734 inclusion_buffer_sofar += strlen(buf) + 1;
1735 clipn++;
1737 x_fclose(inclusion);
1739 if (! error) {
1740 /* Allocate an array of clipn + 1 char*'s for cliplist */
1741 cliplist = SMB_MALLOC_ARRAY(char *, clipn + 1);
1742 if (cliplist == NULL) {
1743 DEBUG(0,("failure allocating memory for cliplist\n"));
1744 error = 1;
1745 } else {
1746 cliplist[clipn] = NULL;
1747 p = inclusion_buffer;
1748 for (i = 0; (! error) && (i < clipn); i++) {
1749 /* set current item to NULL so array will be null-terminated even if
1750 * malloc fails below. */
1751 cliplist[i] = NULL;
1752 if ((tmpstr = (char *)SMB_MALLOC(strlen(p)+1)) == NULL) {
1753 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
1754 error = 1;
1755 } else {
1756 unfixtarname(tmpstr, p, strlen(p) + 1, True);
1757 cliplist[i] = tmpstr;
1758 if ((p = strchr_m(p, '\000')) == NULL) {
1759 DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1760 abort();
1763 ++p;
1765 must_free_cliplist = True;
1769 SAFE_FREE(inclusion_buffer);
1770 if (error) {
1771 if (cliplist) {
1772 char **pp;
1773 /* We know cliplist is always null-terminated */
1774 for (pp = cliplist; *pp; ++pp) {
1775 SAFE_FREE(*pp);
1777 SAFE_FREE(cliplist);
1778 cliplist = NULL;
1779 must_free_cliplist = False;
1781 return 0;
1784 /* cliplist and its elements are freed at the end of process_tar. */
1785 return 1;
1788 /****************************************************************************
1789 Parse tar arguments. Sets tar_type, tar_excl, etc.
1790 ***************************************************************************/
1792 int tar_parseargs(int argc, char *argv[], const char *Optarg, int Optind)
1794 int newOptind = Optind;
1795 char tar_clipfl='\0';
1797 /* Reset back to defaults - could be from interactive version
1798 * reset mode and archive mode left as they are though
1800 tar_type='\0';
1801 tar_excl=True;
1802 dry_run=False;
1804 while (*Optarg) {
1805 switch(*Optarg++) {
1806 case 'c':
1807 tar_type='c';
1808 break;
1809 case 'x':
1810 if (tar_type=='c') {
1811 printf("Tar must be followed by only one of c or x.\n");
1812 return 0;
1814 tar_type='x';
1815 break;
1816 case 'b':
1817 if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1818 DEBUG(0,("Option b must be followed by valid blocksize\n"));
1819 return 0;
1820 } else {
1821 Optind++;
1822 newOptind++;
1824 break;
1825 case 'g':
1826 tar_inc=True;
1827 break;
1828 case 'N':
1829 if (Optind>=argc) {
1830 DEBUG(0,("Option N must be followed by valid file name\n"));
1831 return 0;
1832 } else {
1833 SMB_STRUCT_STAT stbuf;
1835 if (sys_stat(argv[Optind], &stbuf,
1836 false) == 0) {
1837 newer_than = convert_timespec_to_time_t(
1838 stbuf.st_ex_mtime);
1839 DEBUG(1,("Getting files newer than %s",
1840 time_to_asc(newer_than)));
1841 newOptind++;
1842 Optind++;
1843 } else {
1844 DEBUG(0,("Error setting newer-than time\n"));
1845 return 0;
1848 break;
1849 case 'a':
1850 tar_reset=True;
1851 break;
1852 case 'q':
1853 tar_noisy=False;
1854 break;
1855 case 'I':
1856 if (tar_clipfl) {
1857 DEBUG(0,("Only one of I,X,F must be specified\n"));
1858 return 0;
1860 tar_clipfl='I';
1861 break;
1862 case 'X':
1863 if (tar_clipfl) {
1864 DEBUG(0,("Only one of I,X,F must be specified\n"));
1865 return 0;
1867 tar_clipfl='X';
1868 break;
1869 case 'F':
1870 if (tar_clipfl) {
1871 DEBUG(0,("Only one of I,X,F must be specified\n"));
1872 return 0;
1874 tar_clipfl='F';
1875 break;
1876 case 'r':
1877 DEBUG(0, ("tar_re_search set\n"));
1878 tar_re_search = True;
1879 break;
1880 case 'n':
1881 if (tar_type == 'c') {
1882 DEBUG(0, ("dry_run set\n"));
1883 dry_run = True;
1884 } else {
1885 DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1886 return 0;
1888 break;
1889 default:
1890 DEBUG(0,("Unknown tar option\n"));
1891 return 0;
1895 if (!tar_type) {
1896 printf("Option T must be followed by one of c or x.\n");
1897 return 0;
1900 /* tar_excl is true if cliplist lists files to be included.
1901 * Both 'I' and 'F' mean include. */
1902 tar_excl=tar_clipfl!='X';
1904 if (tar_clipfl=='F') {
1905 if (argc-Optind-1 != 1) {
1906 DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1907 return 0;
1909 newOptind++;
1910 /* Optind points at the tar output file, Optind+1 at the inclusion file. */
1911 if (! read_inclusion_file(argv[Optind+1])) {
1912 return 0;
1914 } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
1915 char *tmpstr;
1916 char **tmplist;
1917 int clipcount;
1919 cliplist=argv+Optind+1;
1920 clipn=argc-Optind-1;
1921 clipcount = clipn;
1923 if ((tmplist=SMB_MALLOC_ARRAY(char *,clipn)) == NULL) {
1924 DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n", clipn));
1925 return 0;
1928 for (clipcount = 0; clipcount < clipn; clipcount++) {
1930 DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1932 if ((tmpstr = (char *)SMB_MALLOC(strlen(cliplist[clipcount])+1)) == NULL) {
1933 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", clipcount));
1934 SAFE_FREE(tmplist);
1935 return 0;
1938 unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
1939 tmplist[clipcount] = tmpstr;
1940 DEBUG(5, ("Processed an item, %s\n", tmpstr));
1942 DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1945 cliplist = tmplist;
1946 must_free_cliplist = True;
1948 newOptind += clipn;
1951 if (Optind+1<argc && tar_re_search && tar_clipfl != 'F') {
1952 /* Doing regular expression seaches not from an inclusion file. */
1953 clipn=argc-Optind-1;
1954 cliplist=argv+Optind+1;
1955 newOptind += clipn;
1958 if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1959 /* Sets tar handle to either 0 or 1, as appropriate */
1960 tarhandle=(tar_type=='c');
1962 * Make sure that dbf points to stderr if we are using stdout for
1963 * tar output
1965 if (tarhandle == 1) {
1966 setup_logging("smbclient", DEBUG_STDERR);
1968 if (!argv[Optind]) {
1969 DEBUG(0,("Must specify tar filename\n"));
1970 return 0;
1972 if (!strcmp(argv[Optind], "-")) {
1973 newOptind++;
1976 } else {
1977 if (tar_type=='c' && dry_run) {
1978 tarhandle=-1;
1979 } else if ((tar_type=='x' && (tarhandle = open(argv[Optind], O_RDONLY, 0)) == -1)
1980 || (tar_type=='c' && (tarhandle=creat(argv[Optind], 0644)) < 0)) {
1981 DEBUG(0,("Error opening local file %s - %s\n", argv[Optind], strerror(errno)));
1982 return(0);
1984 newOptind++;
1987 return newOptind;