Added E Jay Berkenbilt's fixes
[Samba/gbeck.git] / source3 / client / clitar.c
blobc841ff982cc884a06b2255d6f8171827b1614d99
1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
4 Tar Extensions
5 Copyright (C) Ricky Poulten 1995-1998
6 Copyright (C) Richard Sharpe 1998
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 /* The following changes developed by Richard Sharpe for Canon Information
23 Systems Research Australia (CISRA)
25 1. Restore can now restore files with long file names
26 2. Save now saves directory information so that we can restore
27 directory creation times
28 3. tar now accepts both UNIX path names and DOS path names. I prefer
29 those lovely /'s to those UGLY \'s :-)
30 4. the files to exclude can be specified as a regular expression by adding
31 an r flag to the other tar flags. Eg:
33 -TcrX file.tar "*.(obj|exe)"
35 will skip all .obj and .exe files
39 #include "includes.h"
40 #include "clitar.h"
42 static int clipfind(char **aret, int ret, char *tok);
44 typedef struct file_info_struct file_info2;
46 struct file_info_struct
48 int size;
49 int mode;
50 int uid;
51 int gid;
52 /* These times are normally kept in GMT */
53 time_t mtime;
54 time_t atime;
55 time_t ctime;
56 char *name; /* This is dynamically allocate */
58 file_info2 *next, *prev; /* Used in the stack ... */
62 typedef struct
64 file_info2 *top;
65 int items;
67 } stack;
69 stack dir_stack = {NULL, 0}; /* Want an empty stack */
71 extern BOOL recurse;
73 #define SEPARATORS " \t\n\r"
74 extern int DEBUGLEVEL;
75 extern int Client;
77 /* These defines are for the do_setrattr routine, to indicate
78 * setting and reseting of file attributes in the function call */
79 #define ATTRSET 1
80 #define ATTRRESET 0
82 static int attribute = aDIR | aSYSTEM | aHIDDEN;
84 #ifndef CLIENT_TIMEOUT
85 #define CLIENT_TIMEOUT (30*1000)
86 #endif
88 static char *tarbuf, *buffer_p;
89 static int tp, ntarf, tbufsiz, ttarf;
90 /* Incremental mode */
91 BOOL tar_inc=False;
92 /* Reset archive bit */
93 BOOL tar_reset=False;
94 /* Include / exclude mode (true=include, false=exclude) */
95 BOOL tar_excl=True;
96 /* use regular expressions for search on file names */
97 BOOL tar_re_search=False;
98 #ifdef HAVE_REGEX_H
99 regex_t *preg;
100 #endif
101 /* Do not dump anything, just calculate sizes */
102 BOOL dry_run=False;
103 /* Dump files with System attribute */
104 BOOL tar_system=True;
105 /* Dump files with Hidden attribute */
106 BOOL tar_hidden=True;
107 /* Be noisy - make a catalogue */
108 BOOL tar_noisy=True;
109 BOOL tar_real_noisy=False; /* Don't want to be really noisy by default */
111 char tar_type='\0';
112 static char **cliplist=NULL;
113 static int clipn=0;
114 static BOOL must_free_cliplist = False;
116 extern file_info def_finfo;
117 extern BOOL lowercase;
118 extern uint16 cnum;
119 extern BOOL readbraw_supported;
120 extern int max_xmit;
121 extern pstring cur_dir;
122 extern int get_total_time_ms;
123 extern int get_total_size;
124 extern int Protocol;
126 int blocksize=20;
127 int tarhandle;
129 static void writetarheader(int f, char *aname, int size, time_t mtime,
130 char *amode, unsigned char ftype);
131 static void do_atar(char *rname,char *lname,file_info *finfo1);
132 static void do_tar(file_info *finfo);
133 static void oct_it(long value, int ndgs, char *p);
134 static void fixtarname(char *tptr, char *fp, int l);
135 static int dotarbuf(int f, char *b, int n);
136 static void dozerobuf(int f, int n);
137 static void dotareof(int f);
138 static void initarbuf(void);
139 static int do_setrattr(char *fname, int attr, int setit);
141 /* restore functions */
142 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix);
143 static long unoct(char *p, int ndgs);
144 static void do_tarput(void);
145 static void unfixtarname(char *tptr, char *fp, int l, BOOL first);
148 * tar specific utitlities
151 #if 0 /* Removed to get around gcc 'defined but not used' error. */
154 * Stack routines, push_dir, pop_dir, top_dir_name
157 static BOOL push_dir(stack *tar_dir_stack, file_info2 *dir)
159 dir -> next = tar_dir_stack -> top;
160 dir -> prev = NULL;
161 tar_dir_stack -> items++;
162 tar_dir_stack -> top = dir;
163 return(True);
167 static file_info2 *pop_dir(stack *tar_dir_stack)
169 file_info2 *ptr;
171 ptr = tar_dir_stack -> top;
172 if (tar_dir_stack -> top != NULL) {
174 tar_dir_stack -> top = tar_dir_stack -> top -> next;
175 tar_dir_stack -> items--;
179 return ptr;
183 static char *top_dir_name(stack *tar_dir_stack)
186 return(tar_dir_stack -> top != NULL?tar_dir_stack -> top -> name:NULL);
190 static BOOL sub_dir(char *dir1, char *dir2)
193 return(True);
197 #endif /* Removed to get around gcc 'defined but not used' error. */
199 /*******************************************************************
200 Create a string of size size+1 (for the null)
201 *******************************************************************/
202 static char *string_create_s(int size)
204 char *tmp;
206 tmp = (char *)malloc(size+1);
208 if (tmp == NULL) {
210 DEBUG(0, ("Out of memory in string_create_s\n"));
214 return(tmp);
218 /****************************************************************************
219 Write a tar header to buffer
220 ****************************************************************************/
221 static void writetarheader(int f, char *aname, int size, time_t mtime,
222 char *amode, unsigned char ftype)
224 union hblock hb;
225 int i, chk, l;
226 char *jp;
228 DEBUG(5, ("WriteTarHdr, Type = %c, Size= %i, Name = %s\n", ftype, size, aname));
230 memset(hb.dummy, 0, sizeof(hb.dummy));
232 l=strlen(aname);
233 if (l >= NAMSIZ) {
234 /* write a GNU tar style long header */
235 char *b;
236 b = (char *)malloc(l+TBLOCK+100);
237 if (!b) {
238 DEBUG(0,("out of memory\n"));
239 exit(1);
241 writetarheader(f, "/./@LongLink", l+1, 0, " 0 \0", 'L');
242 memset(b, 0, l+TBLOCK+100);
243 fixtarname(b, aname, l);
244 i = strlen(b)+1;
245 DEBUG(5, ("File name in tar file: %s, size=%i, \n", b, strlen(b)));
246 dotarbuf(f, b, TBLOCK*(((i-1)/TBLOCK)+1));
247 free(b);
250 /* use l + 1 to do the null too */
251 fixtarname(hb.dbuf.name, aname, (l >= NAMSIZ) ? NAMSIZ : l + 1);
253 if (lowercase)
254 strlower(hb.dbuf.name);
256 /* write out a "standard" tar format header */
258 hb.dbuf.name[NAMSIZ-1]='\0';
259 safe_strcpy(hb.dbuf.mode, amode, strlen(amode));
260 oct_it(0L, 8, hb.dbuf.uid);
261 oct_it(0L, 8, hb.dbuf.gid);
262 oct_it((long) size, 13, hb.dbuf.size);
263 oct_it((long) mtime, 13, hb.dbuf.mtime);
264 memcpy(hb.dbuf.chksum, " ", sizeof(hb.dbuf.chksum));
265 memset(hb.dbuf.linkname, 0, NAMSIZ);
266 hb.dbuf.linkflag=ftype;
268 for (chk=0, i=sizeof(hb.dummy), jp=hb.dummy; --i>=0;) chk+=(0xFF & *jp++);
270 oct_it((long) chk, 8, hb.dbuf.chksum);
271 hb.dbuf.chksum[6] = '\0';
273 (void) dotarbuf(f, hb.dummy, sizeof(hb.dummy));
276 /****************************************************************************
277 Read a tar header into a hblock structure, and validate
278 ***************************************************************************/
279 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix)
281 long chk, fchk;
282 int i;
283 char *jp;
286 * read in a "standard" tar format header - we're not that interested
287 * in that many fields, though
290 /* check the checksum */
291 for (chk=0, i=sizeof(hb->dummy), jp=hb->dummy; --i>=0;) chk+=(0xFF & *jp++);
293 if (chk == 0)
294 return chk;
296 /* compensate for blanks in chksum header */
297 for (i=sizeof(hb->dbuf.chksum), jp=hb->dbuf.chksum; --i>=0;)
298 chk-=(0xFF & *jp++);
300 chk += ' ' * sizeof(hb->dbuf.chksum);
302 fchk=unoct(hb->dbuf.chksum, sizeof(hb->dbuf.chksum));
304 DEBUG(5, ("checksum totals chk=%ld fchk=%ld chksum=%s\n",
305 chk, fchk, hb->dbuf.chksum));
307 if (fchk != chk)
309 DEBUG(0, ("checksums don't match %ld %ld\n", fchk, chk));
310 dump_data(5, (char *)hb - TBLOCK, TBLOCK *3);
311 return -1;
314 if ((finfo->name = string_create_s(strlen(prefix) + strlen(hb -> dbuf.name) + 3)) == NULL) {
316 DEBUG(0, ("Out of space creating file_info2 for %s\n", hb -> dbuf.name));
317 return(-1);
321 safe_strcpy(finfo->name, prefix, strlen(prefix) + strlen(hb -> dbuf.name) + 3);
323 /* use l + 1 to do the null too; do prefix - prefcnt to zap leading slash */
324 unfixtarname(finfo->name + strlen(prefix), hb->dbuf.name,
325 strlen(hb->dbuf.name) + 1, True);
327 /* can't handle some links at present */
328 if ((hb->dbuf.linkflag != '0') && (hb -> dbuf.linkflag != '5')) {
329 if (hb->dbuf.linkflag == 0) {
330 DEBUG(6, ("Warning: NULL link flag (gnu tar archive ?) %s\n",
331 finfo->name));
332 } else {
333 if (hb -> dbuf.linkflag == 'L') { /* We have a longlink */
334 /* Do nothing here at the moment. do_tarput will handle this
335 as long as the longlink gets back to it, as it has to advance
336 the buffer pointer, etc */
338 } else {
339 DEBUG(0, ("this tar file appears to contain some kind of link other than a GNUtar Longlink - ignoring\n"));
340 return -2;
345 if ((unoct(hb->dbuf.mode, sizeof(hb->dbuf.mode)) & S_IFDIR)
346 || (*(finfo->name+strlen(finfo->name)-1) == '\\'))
348 finfo->mode=aDIR;
350 else
351 finfo->mode=0; /* we don't care about mode at the moment, we'll
352 * just make it a regular file */
354 * Bug fix by richard@sj.co.uk
356 * REC: restore times correctly (as does tar)
357 * We only get the modification time of the file; set the creation time
358 * from the mod. time, and the access time to current time
360 finfo->mtime = finfo->ctime = strtol(hb->dbuf.mtime, NULL, 8);
361 finfo->atime = time(NULL);
362 finfo->size = unoct(hb->dbuf.size, sizeof(hb->dbuf.size));
364 return True;
367 /****************************************************************************
368 Write out the tar buffer to tape or wherever
369 ****************************************************************************/
370 static int dotarbuf(int f, char *b, int n)
372 int fail=1, writ=n;
374 if (dry_run) {
375 return writ;
377 /* This routine and the next one should be the only ones that do write()s */
378 if (tp + n >= tbufsiz)
380 int diff;
382 diff=tbufsiz-tp;
383 memcpy(tarbuf + tp, b, diff);
384 fail=fail && (1+write(f, tarbuf, tbufsiz));
385 n-=diff;
386 b+=diff;
387 tp=0;
389 while (n >= tbufsiz)
391 fail=fail && (1 + write(f, b, tbufsiz));
392 n-=tbufsiz;
393 b+=tbufsiz;
396 if (n>0) {
397 memcpy(tarbuf+tp, b, n);
398 tp+=n;
401 return(fail ? writ : 0);
404 /****************************************************************************
405 Write zeros to buffer / tape
406 ****************************************************************************/
407 static void dozerobuf(int f, int n)
409 /* short routine just to write out n zeros to buffer -
410 * used to round files to nearest block
411 * and to do tar EOFs */
413 if (dry_run)
414 return;
416 if (n+tp >= tbufsiz)
418 memset(tarbuf+tp, 0, tbufsiz-tp);
420 write(f, tarbuf, tbufsiz);
421 memset(tarbuf, 0, (tp+=n-tbufsiz));
423 else
425 memset(tarbuf+tp, 0, n);
426 tp+=n;
430 /****************************************************************************
431 Malloc tape buffer
432 ****************************************************************************/
433 static void initarbuf(void)
435 /* initialize tar buffer */
436 tbufsiz=blocksize*TBLOCK;
437 tarbuf=malloc(tbufsiz); /* FIXME: We might not get the buffer */
439 /* reset tar buffer pointer and tar file counter and total dumped */
440 tp=0; ntarf=0; ttarf=0;
443 /****************************************************************************
444 Write two zero blocks at end of file
445 ****************************************************************************/
446 static void dotareof(int f)
448 SMB_STRUCT_STAT stbuf;
449 /* Two zero blocks at end of file, write out full buffer */
451 if (dry_run)
452 return;
454 (void) dozerobuf(f, TBLOCK);
455 (void) dozerobuf(f, TBLOCK);
457 if (sys_fstat(f, &stbuf) == -1)
459 DEBUG(0, ("Couldn't stat file handle\n"));
460 return;
463 /* Could be a pipe, in which case S_ISREG should fail,
464 * and we should write out at full size */
465 if (tp > 0) write(f, tarbuf, S_ISREG(stbuf.st_mode) ? tp : tbufsiz);
468 /****************************************************************************
469 (Un)mangle DOS pathname, make nonabsolute
470 ****************************************************************************/
471 static void fixtarname(char *tptr, char *fp, int l)
473 /* add a '.' to start of file name, convert from ugly dos \'s in path
474 * to lovely unix /'s :-} */
476 *tptr++='.';
478 while (l > 0) {
479 int skip;
480 if((skip = skip_multibyte_char( *fp)) != 0) {
481 if (skip == 2) {
482 *tptr++ = *fp++;
483 *tptr++ = *fp++;
484 l -= 2;
485 } else if (skip == 1) {
486 *tptr++ = *fp++;
487 l--;
489 } else if (*fp == '\\') {
490 *tptr++ = '/';
491 fp++;
492 l--;
493 } else {
494 *tptr++ = *fp++;
495 l--;
500 /****************************************************************************
501 Convert from decimal to octal string
502 ****************************************************************************/
503 static void oct_it (long value, int ndgs, char *p)
505 /* Converts long to octal string, pads with leading zeros */
507 /* skip final null, but do final space */
508 --ndgs;
509 p[--ndgs] = ' ';
511 /* Loop does at least one digit */
512 do {
513 p[--ndgs] = '0' + (char) (value & 7);
514 value >>= 3;
516 while (ndgs > 0 && value != 0);
518 /* Do leading zeros */
519 while (ndgs > 0)
520 p[--ndgs] = '0';
523 /****************************************************************************
524 Convert from octal string to long
525 ***************************************************************************/
526 static long unoct(char *p, int ndgs)
528 long value=0;
529 /* Converts octal string to long, ignoring any non-digit */
531 while (--ndgs)
533 if (isdigit((int)*p))
534 value = (value << 3) | (long) (*p - '0');
536 p++;
539 return value;
542 /****************************************************************************
543 Compare two strings in a slash insensitive way, allowing s1 to match s2
544 if s1 is an "initial" string (up to directory marker). Thus, if s2 is
545 a file in any subdirectory of s1, declare a match.
546 ***************************************************************************/
547 static int strslashcmp(char *s1, char *s2)
549 char *s1_0=s1;
551 while(*s1 && *s2 &&
552 (*s1 == *s2
553 || tolower(*s1) == tolower(*s2)
554 || (*s1 == '\\' && *s2=='/')
555 || (*s1 == '/' && *s2=='\\'))) {
556 s1++; s2++;
559 /* if s1 has a trailing slash, it compared equal, so s1 is an "initial"
560 string of s2.
562 if (!*s1 && s1 != s1_0 && (*(s1-1) == '/' || *(s1-1) == '\\')) return 0;
564 /* ignore trailing slash on s1 */
565 if (!*s2 && (*s1 == '/' || *s1 == '\\') && !*(s1+1)) return 0;
567 /* check for s1 is an "initial" string of s2 */
568 if (*s2 == '/' || *s2 == '\\') return 0;
570 return *s1-*s2;
574 * general smb utility functions
576 /**********************************************************************
577 do_setrtime, set time on a file or dir ...
578 **********************************************************************/
580 static int do_setrtime(char *fname, int mtime, BOOL err_silent)
582 char *inbuf, *outbuf, *p;
583 char *name;
585 DEBUG(5, ("Setting time on: %s, fnlen=%i.\n", fname, strlen(fname)));
587 name = (char *)malloc(strlen(fname) + 1 + 1);
588 if (name == NULL) {
590 DEBUG(0, ("Failed to allocate space while setting time on file: %s", fname));
591 return False;
595 if (*fname != '\\')
596 safe_strcpy(name, "\\", strlen(fname) + 1);
597 else
598 safe_strcpy(name, "", strlen(fname) + 1);
599 safe_strcat(name, fname, strlen(fname) + 1);
601 if (fname[strlen(name) - 1] == '\\')
602 name[strlen(name) - 1] = '\0';
604 inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
605 outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
607 if (!inbuf || !outbuf) {
609 DEBUG(0, ("Could not allocate memory for inbuf or outbuf while changing time on: %s\n", fname));
610 free(name);
611 return False;
615 memset(outbuf, 0, smb_size);
616 set_message(outbuf, 8, 4 + strlen(name), True);
617 CVAL(outbuf, smb_com) = SMBsetatr;
618 SSVAL(outbuf, smb_tid, cnum);
619 cli_setup_pkt(outbuf);
621 SSVAL(outbuf, smb_vwv0, 0);
622 put_dos_date3(outbuf, smb_vwv1, mtime);
624 p = smb_buf(outbuf);
625 *p++ = 4;
626 safe_strcpy(p, name, strlen(name));
627 p+= (strlen(fname)+1);
629 *p++ = 4;
630 *p++ = 0;
632 send_smb(Client, outbuf);
633 client_receive_smb(Client, inbuf, CLIENT_TIMEOUT);
635 if (CVAL(inbuf,smb_rcls) != 0)
637 if (!err_silent) {
638 DEBUG(0,("%s setting attributes on file %s\n",
639 smb_errstr(inbuf), fname));
641 free(name);free(inbuf);free(outbuf);
642 return(False);
645 free(name);
646 free(inbuf);free(outbuf);
647 return(True);
651 /****************************************************************************
652 Set DOS file attributes
653 ***************************************************************************/
654 static int do_setrattr(char *fname, int attr, int setit)
657 * First get the existing attribs from existing file
659 char *inbuf,*outbuf;
660 char *p;
661 char *name;
662 int fattr;
664 name = (char *)malloc(strlen(fname) + 1 + 1);
665 if (name == NULL) {
667 DEBUG(0, ("Failed to allocate space in do_setrattr while setting time on file: %s", fname));
668 return False;
672 safe_strcpy(name, "\\", strlen(fname) + 1);
673 safe_strcat(name, fname, strlen(fname) + 1);
675 inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
676 outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
678 if (!inbuf || !outbuf)
680 DEBUG(0,("out of memory\n"));
681 free(name);
682 return False;
685 /* send an smb getatr message */
687 memset(outbuf,0,smb_size);
688 set_message(outbuf,0,2 + strlen(fname),True);
689 CVAL(outbuf,smb_com) = SMBgetatr;
690 SSVAL(outbuf,smb_tid,cnum);
691 cli_setup_pkt(outbuf);
693 p = smb_buf(outbuf);
694 *p++ = 4;
695 safe_strcpy(p,name, strlen(name));
696 p += (strlen(name)+1);
698 *p++ = 4;
699 *p++ = 0;
701 send_smb(Client,outbuf);
702 client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
704 if (CVAL(inbuf,smb_rcls) != 0)
705 DEBUG(5,("getatr: %s\n",smb_errstr(inbuf)));
706 else
708 DEBUG(5,("\nattr 0x%X time %d size %d\n",
709 (int)CVAL(inbuf,smb_vwv0),
710 SVAL(inbuf,smb_vwv1),
711 SVAL(inbuf,smb_vwv3)));
714 fattr=CVAL(inbuf,smb_vwv0);
716 /* combine found attributes with bits to be set or reset */
718 attr=setit ? (fattr | attr) : (fattr & ~attr);
720 /* now try and set attributes by sending smb reset message */
722 /* clear out buffer and start again */
723 memset(outbuf,0,smb_size);
724 set_message(outbuf,8,4 + strlen(name),True);
725 CVAL(outbuf,smb_com) = SMBsetatr;
726 SSVAL(outbuf,smb_tid,cnum);
727 cli_setup_pkt(outbuf);
729 SSVAL(outbuf,smb_vwv0,attr);
731 p = smb_buf(outbuf);
732 *p++ = 4;
733 safe_strcpy(p,name, strlen(name));
734 p += (strlen(name)+1);
736 *p++ = 4;
737 *p++ = 0;
739 send_smb(Client,outbuf);
740 client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
742 if (CVAL(inbuf,smb_rcls) != 0)
744 DEBUG(0,("%s setting attributes on file %s\n",
745 smb_errstr(inbuf), name));
746 free(name);free(inbuf);free(outbuf);
747 return(False);
750 free(name);
751 free(inbuf);free(outbuf);
752 return(True);
755 /****************************************************************************
756 Create a file on a share
757 ***************************************************************************/
758 static BOOL smbcreat(file_info2 finfo, int *fnum, char *inbuf, char *outbuf)
760 char *p;
761 /* *must* be called with buffer ready malloc'ed */
762 /* open remote file */
764 memset(outbuf,0,smb_size);
765 set_message(outbuf,3,2 + strlen(finfo.name),True);
766 CVAL(outbuf,smb_com) = SMBcreate;
767 SSVAL(outbuf,smb_tid,cnum);
768 cli_setup_pkt(outbuf);
770 SSVAL(outbuf,smb_vwv0,finfo.mode);
771 put_dos_date3(outbuf,smb_vwv1,finfo.mtime);
773 p = smb_buf(outbuf);
774 *p++ = 4;
775 safe_strcpy(p,finfo.name, strlen(finfo.name));
777 send_smb(Client,outbuf);
778 client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
780 if (CVAL(inbuf,smb_rcls) != 0)
782 DEBUG(0,("%s opening remote file %s\n",smb_errstr(inbuf),
783 finfo.name));
784 return 0;
787 *fnum = SVAL(inbuf,smb_vwv0);
788 return True;
791 /****************************************************************************
792 Write a file to a share
793 ***************************************************************************/
794 static BOOL smbwrite(int fnum, int n, int low, int high, int left,
795 char *bufferp, char *inbuf, char *outbuf)
797 /* *must* be called with buffer ready malloc'ed */
799 memset(outbuf,0,smb_size);
800 set_message(outbuf,5,n + 3,True);
802 memcpy(smb_buf(outbuf)+3, bufferp, n);
804 set_message(outbuf,5,n + 3, False);
805 CVAL(outbuf,smb_com) = SMBwrite;
806 SSVAL(outbuf,smb_tid,cnum);
807 cli_setup_pkt(outbuf);
809 SSVAL(outbuf,smb_vwv0,fnum);
810 SSVAL(outbuf,smb_vwv1,n);
811 SIVAL(outbuf,smb_vwv2,low);
812 SSVAL(outbuf,smb_vwv4,left);
813 CVAL(smb_buf(outbuf),0) = 1;
814 SSVAL(smb_buf(outbuf),1,n);
816 send_smb(Client,outbuf);
817 client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
819 if (CVAL(inbuf,smb_rcls) != 0)
821 DEBUG(0,("%s writing remote file\n",smb_errstr(inbuf)));
822 return False;
825 if (n != SVAL(inbuf,smb_vwv0))
827 DEBUG(0,("Error: only wrote %d bytes out of %d\n",
828 SVAL(inbuf,smb_vwv0), n));
829 return False;
832 return True;
835 /****************************************************************************
836 Close a file on a share
837 ***************************************************************************/
838 static BOOL smbshut(file_info2 finfo, int fnum, char *inbuf, char *outbuf)
840 /* *must* be called with buffer ready malloc'ed */
842 memset(outbuf,0,smb_size);
843 set_message(outbuf,3,0,True);
844 CVAL(outbuf,smb_com) = SMBclose;
845 SSVAL(outbuf,smb_tid,cnum);
846 cli_setup_pkt(outbuf);
848 SSVAL(outbuf,smb_vwv0,fnum);
849 put_dos_date3(outbuf,smb_vwv1,finfo.mtime);
851 DEBUG(3,("Setting date to %s (0x%lX)",
852 asctime(LocalTime(&finfo.mtime)),
853 finfo.mtime));
855 send_smb(Client,outbuf);
856 client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
858 if (CVAL(inbuf,smb_rcls) != 0)
860 DEBUG(0,("%s closing remote file %s\n",smb_errstr(inbuf),
861 finfo.name));
862 return False;
865 return True;
868 /****************************************************************************
869 Verify existence of path on share
870 ***************************************************************************/
871 static BOOL smbchkpath(char *fname, char *inbuf, char *outbuf)
873 char *p;
875 memset(outbuf,0,smb_size);
876 set_message(outbuf,0,4 + strlen(fname),True);
877 CVAL(outbuf,smb_com) = SMBchkpth;
878 SSVAL(outbuf,smb_tid,cnum);
879 cli_setup_pkt(outbuf);
881 p = smb_buf(outbuf);
882 *p++ = 4;
883 safe_strcpy(p,fname, strlen(fname));
885 send_smb(Client,outbuf);
886 client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
888 DEBUG(5,("smbchkpath: %s\n",smb_errstr(inbuf)));
890 return(CVAL(inbuf,smb_rcls) == 0);
893 /****************************************************************************
894 Make a directory on share
895 ***************************************************************************/
896 static BOOL smbmkdir(char *fname, char *inbuf, char *outbuf)
898 /* *must* be called with buffer ready malloc'ed */
899 char *p;
901 memset(outbuf,0,smb_size);
902 set_message(outbuf,0,2 + strlen(fname),True);
904 CVAL(outbuf,smb_com) = SMBmkdir;
905 SSVAL(outbuf,smb_tid,cnum);
906 cli_setup_pkt(outbuf);
908 p = smb_buf(outbuf);
909 *p++ = 4;
910 safe_strcpy(p,fname, strlen(fname));
912 send_smb(Client,outbuf);
913 client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
915 if (CVAL(inbuf,smb_rcls) != 0)
917 DEBUG(0,("%s making remote directory %s\n",
918 smb_errstr(inbuf),fname));
919 return(False);
922 return(True);
925 /****************************************************************************
926 Ensure a remote path exists (make if necessary)
927 ***************************************************************************/
928 static BOOL ensurepath(char *fname, char *inbuf, char *outbuf)
930 /* *must* be called with buffer ready malloc'ed */
931 /* ensures path exists */
933 char *partpath, *ffname;
934 char *p=fname, *basehack;
936 DEBUG(5, ( "Ensurepath called with: %s\n", fname));
938 partpath = string_create_s(strlen(fname));
939 ffname = string_create_s(strlen(fname));
941 if ((partpath == NULL) || (ffname == NULL)){
943 DEBUG(0, ("Out of memory in ensurepath: %s\n", fname));
944 return(False);
948 *partpath = 0;
950 /* fname copied to ffname so can strtok */
952 safe_strcpy(ffname, fname, strlen(fname));
954 /* do a `basename' on ffname, so don't try and make file name directory */
955 if ((basehack=strrchr(ffname, '\\')) == NULL)
956 return True;
957 else
958 *basehack='\0';
960 p=strtok(ffname, "\\");
962 while (p)
964 safe_strcat(partpath, p, strlen(fname) + 1);
966 if (!smbchkpath(partpath, inbuf, outbuf)) {
967 if (!smbmkdir(partpath, inbuf, outbuf))
969 DEBUG(0, ("Error mkdirhiering\n"));
970 return False;
972 else
973 DEBUG(3, ("mkdirhiering %s\n", partpath));
977 safe_strcat(partpath, "\\", strlen(fname) + 1);
978 p = strtok(NULL,"/\\");
981 return True;
984 static int padit(char *buf, int bufsize, int padsize)
986 int berr= 0;
987 int bytestowrite;
989 DEBUG(5, ("Padding with %d zeros\n", padsize));
990 memset(buf, 0, bufsize);
991 while( !berr && padsize > 0 ) {
992 bytestowrite= MIN(bufsize, padsize);
993 berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite;
994 padsize -= bytestowrite;
997 return berr;
1001 * smbclient functions
1003 /****************************************************************************
1004 append one remote file to the tar file
1005 ***************************************************************************/
1006 static void do_atar(char *rname,char *lname,file_info *finfo1)
1008 int fnum;
1009 uint32 nread=0;
1010 char *p, ftype;
1011 char *inbuf,*outbuf;
1012 file_info2 finfo;
1013 BOOL close_done = False;
1014 BOOL shallitime=True;
1015 BOOL ignore_close_error = False;
1016 char *dataptr=NULL;
1017 int datalen=0;
1019 struct timeval tp_start;
1020 GetTimeOfDay(&tp_start);
1022 ftype = '0'; /* An ordinary file ... */
1024 if (finfo1) {
1025 finfo.size = finfo1 -> size;
1026 finfo.mode = finfo1 -> mode;
1027 finfo.uid = finfo1 -> uid;
1028 finfo.gid = finfo1 -> gid;
1029 finfo.mtime = finfo1 -> mtime;
1030 finfo.atime = finfo1 -> atime;
1031 finfo.ctime = finfo1 -> ctime;
1033 else {
1034 finfo.size = def_finfo.size;
1035 finfo.mode = def_finfo.mode;
1036 finfo.uid = def_finfo.uid;
1037 finfo.gid = def_finfo.gid;
1038 finfo.mtime = def_finfo.mtime;
1039 finfo.atime = def_finfo.atime;
1040 finfo.ctime = def_finfo.ctime;
1043 if (dry_run)
1045 DEBUG(3,("skipping file %s of size %d bytes\n",
1046 finfo.name,
1047 finfo.size));
1048 shallitime=0;
1049 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
1050 ntarf++;
1051 return;
1054 inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1055 outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1057 if (!inbuf || !outbuf)
1059 DEBUG(0,("out of memory\n"));
1060 return;
1063 memset(outbuf,0,smb_size);
1064 set_message(outbuf,15,1 + strlen(rname),True);
1066 CVAL(outbuf,smb_com) = SMBopenX;
1067 SSVAL(outbuf,smb_tid,cnum);
1068 cli_setup_pkt(outbuf);
1070 SSVAL(outbuf,smb_vwv0,0xFF);
1071 SSVAL(outbuf,smb_vwv2,1);
1072 SSVAL(outbuf,smb_vwv3,(DENY_NONE<<4));
1073 SSVAL(outbuf,smb_vwv4,aSYSTEM | aHIDDEN);
1074 SSVAL(outbuf,smb_vwv5,aSYSTEM | aHIDDEN);
1075 SSVAL(outbuf,smb_vwv8,1);
1077 p = smb_buf(outbuf);
1078 safe_strcpy(p, rname, strlen(rname));
1079 p = skip_string(p,1);
1081 dos_clean_name(rname);
1083 /* do a chained openX with a readX? */
1084 if (finfo.size > 0)
1086 SSVAL(outbuf,smb_vwv0,SMBreadX);
1087 SSVAL(outbuf,smb_vwv1,PTR_DIFF(p,outbuf) - 4);
1088 memset(p,0,200);
1089 p -= smb_wct;
1090 SCVAL(p,smb_wct,10);
1091 SSVAL(p,smb_vwv0,0xFF);
1092 SSVAL(p,smb_vwv5,MIN(max_xmit-500,finfo.size));
1093 SSVAL(p,smb_vwv9,MIN(0xFFFF,finfo.size));
1094 smb_setlen(outbuf,smb_len(outbuf)+11*2+1);
1097 send_smb(Client,outbuf);
1098 client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1100 if (CVAL(inbuf,smb_rcls) != 0)
1102 if (CVAL(inbuf,smb_rcls) == ERRSRV &&
1103 SVAL(inbuf,smb_err) == ERRnoresource &&
1104 cli_reopen_connection(inbuf,outbuf))
1106 do_atar(rname,lname,finfo1);
1107 free(inbuf);free(outbuf);
1108 return;
1111 DEBUG(0,("%s opening remote file %s\n",smb_errstr(inbuf),rname));
1112 free(inbuf);free(outbuf);
1113 return;
1116 finfo.name = string_create_s(strlen(rname));
1117 if (finfo.name == NULL) {
1119 DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n"));
1120 free(inbuf); free(outbuf);
1121 return;
1125 safe_strcpy(finfo.name,rname, strlen(rname));
1126 if (!finfo1)
1128 finfo.mode = SVAL(inbuf,smb_vwv3);
1129 finfo.size = IVAL(inbuf,smb_vwv4);
1130 finfo.mtime = make_unix_date3(inbuf+smb_vwv6);
1131 finfo.atime = finfo.ctime = finfo.mtime;
1134 DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
1136 fnum = SVAL(inbuf,smb_vwv2);
1138 if (tar_inc && !(finfo.mode & aARCH))
1140 DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
1141 shallitime=0;
1143 else if (!tar_system && (finfo.mode & aSYSTEM))
1145 DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
1146 shallitime=0;
1148 else if (!tar_hidden && (finfo.mode & aHIDDEN))
1150 DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
1151 shallitime=0;
1153 else
1155 if (SVAL(inbuf,smb_vwv0) == SMBreadX)
1157 p = (inbuf+4+SVAL(inbuf,smb_vwv1)) - smb_wct;
1158 datalen = SVAL(p,smb_vwv5);
1159 dataptr = inbuf + 4 + SVAL(p,smb_vwv6);
1161 else
1163 dataptr = NULL;
1164 datalen = 0;
1167 DEBUG(3,("getting file %s of size %d bytes as a tar file %s",
1168 finfo.name,
1169 finfo.size,
1170 lname));
1172 /* write a tar header, don't bother with mode - just set to 100644 */
1173 writetarheader(tarhandle, rname, finfo.size, finfo.mtime, "100644 \0", ftype);
1175 while (nread < finfo.size && !close_done)
1177 int method = -1;
1178 static BOOL can_chain_close=True;
1180 p=NULL;
1182 DEBUG(3,("nread=%d\n",nread));
1184 /* 3 possible read types. readbraw if a large block is required.
1185 readX + close if not much left and read if neither is supported */
1187 /* we might have already read some data from a chained readX */
1188 if (dataptr && datalen>0)
1189 method=3;
1191 /* if we can finish now then readX+close */
1192 if (method<0 && can_chain_close && (Protocol >= PROTOCOL_LANMAN1) &&
1193 ((finfo.size - nread) <
1194 (max_xmit - (2*smb_size + 13*SIZEOFWORD + 300))))
1195 method = 0;
1197 /* if we support readraw then use that */
1198 if (method<0 && readbraw_supported)
1199 method = 1;
1201 /* if we can then use readX */
1202 if (method<0 && (Protocol >= PROTOCOL_LANMAN1))
1203 method = 2;
1206 switch (method)
1208 /* use readX */
1209 case 0:
1210 case 2:
1211 if (method == 0)
1212 close_done = True;
1214 /* use readX + close */
1215 memset(outbuf,0,smb_size);
1216 set_message(outbuf,10,0,True);
1217 CVAL(outbuf,smb_com) = SMBreadX;
1218 SSVAL(outbuf,smb_tid,cnum);
1219 cli_setup_pkt(outbuf);
1221 if (close_done)
1223 CVAL(outbuf,smb_vwv0) = SMBclose;
1224 SSVAL(outbuf,smb_vwv1,PTR_DIFF(smb_buf(outbuf),outbuf) - 4);
1226 else
1227 CVAL(outbuf,smb_vwv0) = 0xFF;
1230 SSVAL(outbuf,smb_vwv2,fnum);
1231 SIVAL(outbuf,smb_vwv3,nread);
1232 SSVAL(outbuf,smb_vwv5,MIN(max_xmit-200,finfo.size - nread));
1233 SSVAL(outbuf,smb_vwv6,0);
1234 SIVAL(outbuf,smb_vwv7,0);
1235 SSVAL(outbuf,smb_vwv9,MIN(0xFFFF,finfo.size-nread));
1237 if (close_done)
1239 p = smb_buf(outbuf);
1240 memset(p,0,9);
1242 CVAL(p,0) = 3;
1243 SSVAL(p,1,fnum);
1244 SIVALS(p,3,-1);
1246 /* now set the total packet length */
1247 smb_setlen(outbuf,smb_len(outbuf)+9);
1250 send_smb(Client,outbuf);
1251 client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1253 if (CVAL(inbuf,smb_rcls) != 0)
1255 DEBUG(0,("Error %s reading remote file\n",smb_errstr(inbuf)));
1256 break;
1259 if (close_done &&
1260 SVAL(inbuf,smb_vwv0) != SMBclose)
1262 /* NOTE: WfWg sometimes just ignores the chained
1263 command! This seems to break the spec? */
1264 DEBUG(3,("Rejected chained close?\n"));
1265 close_done = False;
1266 can_chain_close = False;
1267 ignore_close_error = True;
1270 datalen = SVAL(inbuf,smb_vwv5);
1271 dataptr = inbuf + 4 + SVAL(inbuf,smb_vwv6);
1272 break;
1275 /* use readbraw */
1276 case 1:
1278 static int readbraw_size = 0xFFFF;
1280 extern int Client;
1281 memset(outbuf,0,smb_size);
1282 set_message(outbuf,8,0,True);
1283 CVAL(outbuf,smb_com) = SMBreadbraw;
1284 SSVAL(outbuf,smb_tid,cnum);
1285 cli_setup_pkt(outbuf);
1286 SSVAL(outbuf,smb_vwv0,fnum);
1287 SIVAL(outbuf,smb_vwv1,nread);
1288 SSVAL(outbuf,smb_vwv3,MIN(finfo.size-nread,readbraw_size));
1289 SSVAL(outbuf,smb_vwv4,0);
1290 SIVALS(outbuf,smb_vwv5,-1);
1291 send_smb(Client,outbuf);
1293 /* Now read the raw data into the buffer and write it */
1294 if(read_smb_length(Client,inbuf,0) == -1) {
1295 DEBUG(0,("Failed to read length in readbraw\n"));
1296 exit(1);
1299 /* Even though this is not an smb message, smb_len
1300 returns the generic length of an smb message */
1301 datalen = smb_len(inbuf);
1303 if (datalen == 0)
1305 /* we got a readbraw error */
1306 DEBUG(4,("readbraw error - reducing size\n"));
1307 readbraw_size = (readbraw_size * 9) / 10;
1309 if (readbraw_size < max_xmit)
1311 DEBUG(0,("disabling readbraw\n"));
1312 readbraw_supported = False;
1315 dataptr=NULL;
1316 continue;
1319 if(read_data(Client,inbuf,datalen) != datalen) {
1320 DEBUG(0,("Failed to read data in readbraw\n"));
1321 exit(1);
1323 dataptr = inbuf;
1325 break;
1327 case 3:
1328 /* we've already read some data with a chained readX */
1329 break;
1331 default:
1332 /* use plain read */
1333 memset(outbuf,0,smb_size);
1334 set_message(outbuf,5,0,True);
1335 CVAL(outbuf,smb_com) = SMBread;
1336 SSVAL(outbuf,smb_tid,cnum);
1337 cli_setup_pkt(outbuf);
1339 SSVAL(outbuf,smb_vwv0,fnum);
1340 SSVAL(outbuf,smb_vwv1,MIN(max_xmit-200,finfo.size - nread));
1341 SIVAL(outbuf,smb_vwv2,nread);
1342 SSVAL(outbuf,smb_vwv4,finfo.size - nread);
1344 send_smb(Client,outbuf);
1345 client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1347 if (CVAL(inbuf,smb_rcls) != 0)
1349 DEBUG(0,("Error %s reading remote file\n",smb_errstr(inbuf)));
1350 break;
1353 datalen = SVAL(inbuf,smb_vwv0);
1354 dataptr = smb_buf(inbuf) + 3;
1355 break;
1359 /* add received bits of file to buffer - dotarbuf will
1360 * write out in 512 byte intervals */
1361 if (dotarbuf(tarhandle,dataptr,datalen) != datalen)
1363 DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
1364 break;
1367 nread += datalen;
1368 if (datalen == 0)
1370 DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
1371 break;
1374 dataptr=NULL;
1375 datalen=0;
1378 /* pad tar file with zero's if we couldn't get entire file */
1379 if (nread < finfo.size)
1381 DEBUG(0, ("Didn't get entire file. size=%d, nread=%d\n", finfo.size, nread));
1382 if (padit(inbuf, BUFFER_SIZE, finfo.size - nread))
1383 DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
1386 /* round tar file to nearest block */
1387 if (finfo.size % TBLOCK)
1388 dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
1390 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
1391 ntarf++;
1394 if (!close_done)
1396 memset(outbuf,0,smb_size);
1397 set_message(outbuf,3,0,True);
1398 CVAL(outbuf,smb_com) = SMBclose;
1399 SSVAL(outbuf,smb_tid,cnum);
1400 cli_setup_pkt(outbuf);
1402 SSVAL(outbuf,smb_vwv0,fnum);
1403 SIVALS(outbuf,smb_vwv1,-1);
1405 send_smb(Client,outbuf);
1406 client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1408 if (!ignore_close_error && CVAL(inbuf,smb_rcls) != 0)
1410 DEBUG(0,("Error %s closing remote file\n",smb_errstr(inbuf)));
1411 free(inbuf);free(outbuf);
1412 return;
1416 if (shallitime)
1418 struct timeval tp_end;
1419 int this_time;
1421 /* if shallitime is true then we didn't skip */
1422 if (tar_reset && !dry_run)
1423 (void) do_setrattr(finfo.name, aARCH, ATTRRESET);
1425 GetTimeOfDay(&tp_end);
1426 this_time =
1427 (tp_end.tv_sec - tp_start.tv_sec)*1000 +
1428 (tp_end.tv_usec - tp_start.tv_usec)/1000;
1429 get_total_time_ms += this_time;
1430 get_total_size += finfo.size;
1432 if (tar_noisy)
1434 DEBUG(0, ("%10d (%7.1f kb/s) %s\n",
1435 finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
1436 finfo.name));
1439 /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
1440 DEBUG(3,("(%g kb/s) (average %g kb/s)\n",
1441 finfo.size / MAX(0.001, (1.024*this_time)),
1442 get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
1445 free(inbuf);free(outbuf);
1448 /****************************************************************************
1449 Append single file to tar file (or not)
1450 ***************************************************************************/
1451 static void do_tar(file_info *finfo)
1453 pstring rname;
1455 if (strequal(finfo->name,".."))
1456 return;
1458 /* Is it on the exclude list ? */
1459 if (!tar_excl && clipn) {
1460 pstring exclaim;
1462 DEBUG(5, ("Excl: strlen(cur_dir) = %i\n", strlen(cur_dir)));
1464 safe_strcpy(exclaim, cur_dir, sizeof(pstring));
1465 *(exclaim+strlen(exclaim)-1)='\0';
1467 safe_strcat(exclaim, "\\", sizeof(pstring));
1468 safe_strcat(exclaim, finfo->name, sizeof(exclaim));
1470 DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
1472 if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
1473 #ifdef HAVE_REGEX_H
1474 (tar_re_search && !regexec(preg, exclaim, 0, NULL, 0))) {
1475 #else
1476 (tar_re_search && mask_match(exclaim, cliplist[0], True, False))) {
1477 #endif
1478 DEBUG(3,("Skipping file %s\n", exclaim));
1479 return;
1483 if (finfo->mode & aDIR)
1485 pstring saved_curdir;
1486 pstring mtar_mask;
1487 char *inbuf,*outbuf;
1489 inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1490 outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1492 if (!inbuf || !outbuf)
1494 DEBUG(0,("out of memory\n"));
1495 return;
1498 safe_strcpy(saved_curdir, cur_dir, sizeof(saved_curdir));
1500 DEBUG(5, ("Sizeof(cur_dir)=%i, strlen(cur_dir)=%i, strlen(finfo->name)=%i\nname=%s,cur_dir=%s\n", sizeof(cur_dir), strlen(cur_dir), strlen(finfo->name), finfo->name, cur_dir));
1502 safe_strcat(cur_dir,finfo->name, sizeof(cur_dir));
1503 safe_strcat(cur_dir,"\\", sizeof(cur_dir));
1505 DEBUG(5, ("Writing a dir, Name = %s\n", cur_dir));
1507 /* write a tar directory, don't bother with mode - just set it to
1508 * 40755 */
1509 writetarheader(tarhandle, cur_dir, 0, finfo->mtime, "040755 \0", '5');
1510 if (tar_noisy) {
1512 DEBUG(0, (" directory %s\n", cur_dir));
1515 ntarf++; /* Make sure we have a file on there */
1516 safe_strcpy(mtar_mask,cur_dir, sizeof(pstring));
1517 safe_strcat(mtar_mask,"*", sizeof(pstring));
1518 /* do_dir((char *)inbuf,(char *)outbuf,mtar_mask,attribute,do_tar,recurse,True); */
1519 safe_strcpy(cur_dir,saved_curdir, sizeof(pstring));
1520 free(inbuf);free(outbuf);
1522 else
1524 safe_strcpy(rname,cur_dir, sizeof(pstring));
1525 safe_strcat(rname,finfo->name, sizeof(pstring));
1526 do_atar(rname,finfo->name,finfo);
1530 /****************************************************************************
1531 Convert from UNIX to DOS file names
1532 ***************************************************************************/
1533 static void unfixtarname(char *tptr, char *fp, int l, BOOL first)
1535 /* remove '.' from start of file name, convert from unix /'s to
1536 * dos \'s in path. Kill any absolute path names. But only if first!
1539 DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
1541 if (first) {
1542 if (*fp == '.') {
1543 fp++;
1544 l--;
1546 if (*fp == '\\' || *fp == '/') {
1547 fp++;
1548 l--;
1552 while (l > 0) {
1553 int skip;
1554 if(( skip = skip_multibyte_char( *fp )) != 0) {
1555 if (skip == 2) {
1556 *tptr++ = *fp++;
1557 *tptr++ = *fp++;
1558 l -= 2;
1559 } else if (skip == 1) {
1560 *tptr++ = *fp++;
1561 l--;
1563 } else if (*fp == '/') {
1564 *tptr++ = '\\';
1565 fp++;
1566 l--;
1567 } else {
1568 *tptr++ = *fp++;
1569 l--;
1574 #ifndef OLD_DOTARPUT
1576 /****************************************************************************
1577 Move to the next block in the buffer, which may mean read in another set of
1578 blocks. FIXME, we should allow more than one block to be skipped.
1579 ****************************************************************************/
1580 static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
1582 int bufread, total = 0;
1584 DEBUG(5, ("Advancing to next block: %0x\n", (unsigned int)*bufferp));
1585 *bufferp += TBLOCK;
1586 total = TBLOCK;
1588 if (*bufferp >= (ltarbuf + bufsiz)) {
1590 DEBUG(5, ("Reading more data into ltarbuf ...\n"));
1592 total = 0;
1594 for (bufread = read(tarhandle, ltarbuf, bufsiz); total < bufsiz; total += bufread) {
1596 if (bufread <= 0) { /* An error, return false */
1597 return (total > 0 ? -2 : bufread);
1602 DEBUG(5, ("Total bytes read ... %i\n", total));
1604 *bufferp = ltarbuf;
1608 return(total);
1612 /* Skip a file, even if it includes a long file name? */
1613 static int skip_file(int skipsize)
1615 int dsize = skipsize;
1617 DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
1619 /* FIXME, we should skip more than one block at a time */
1621 while (dsize > 0) {
1623 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1625 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1626 return(False);
1630 dsize -= TBLOCK;
1634 return(True);
1637 /* We get a file from the tar file and store it */
1638 static int get_file(file_info2 finfo, char * inbuf, char * outbuf)
1640 int fsize = finfo.size;
1641 int fnum, pos = 0, dsize = 0, rsize = 0, bpos = 0;
1643 DEBUG(5, ("get_file: file: %s, size %i\n", finfo.name, fsize));
1645 if (ensurepath(finfo.name, inbuf, outbuf) &&
1646 !smbcreat(finfo, &fnum, inbuf, outbuf))
1648 DEBUG(0, ("abandoning restore\n"));
1649 return(False);
1652 /* read the blocks from the tar file and write to the remote file */
1654 rsize = fsize; /* This is how much to write */
1656 while (rsize > 0) {
1658 /* We can only write up to the end of the buffer */
1660 dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, max_xmit - 50); /* Calculate the size to write */
1661 dsize = MIN(dsize, rsize); /* Should be only what is left */
1662 DEBUG(5, ("writing %i bytes, max_xmit = %i, bpos = %i ...\n", dsize, max_xmit, bpos));
1664 if (!smbwrite(fnum, dsize, pos, 0, fsize - pos, buffer_p + bpos, inbuf, outbuf)) {
1666 DEBUG(0, ("Error writing remote file\n"));
1667 return 0;
1671 rsize -= dsize;
1672 pos += dsize;
1674 /* Now figure out how much to move in the buffer */
1676 /* FIXME, we should skip more than one block at a time */
1678 /* First, skip any initial part of the part written that is left over */
1679 /* from the end of the first TBLOCK */
1681 if ((bpos) && ((bpos + dsize) >= TBLOCK)) {
1683 dsize -= (TBLOCK - bpos); /* Get rid of the end of the first block */
1684 bpos = 0;
1686 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) { /* and skip the block */
1687 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1688 return False;
1694 while (dsize >= TBLOCK) {
1696 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1698 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1699 return False;
1703 dsize -= TBLOCK;
1707 bpos = dsize;
1711 /* Now close the file ... */
1713 if (!smbshut(finfo, fnum, inbuf, outbuf)) {
1715 DEBUG(0, ("Error closing remote file\n"));
1716 return(False);
1720 /* Now we update the creation date ... */
1722 DEBUG(5, ("Updating creation date on %s\n", finfo.name));
1724 if (!do_setrtime(finfo.name, finfo.mtime, True)) {
1726 if (tar_real_noisy) {
1727 DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
1728 /*return(False); */ /* Ignore, as Win95 does not allow changes */
1732 ntarf++;
1734 DEBUG(0, ("restore tar file %s of size %d bytes\n", finfo.name, finfo.size));
1736 return(True);
1740 /* Create a directory. We just ensure that the path exists and return as there
1741 is no file associated with a directory
1743 static int get_dir(file_info2 finfo, char * inbuf, char * outbuf)
1746 DEBUG(5, ("Creating directory: %s\n", finfo.name));
1748 if (!ensurepath(finfo.name, inbuf, outbuf)) {
1750 DEBUG(0, ("Problems creating directory\n"));
1751 return(False);
1754 return(True);
1757 /* Get a file with a long file name ... first file has file name, next file
1758 has the data. We only want the long file name, as the loop in do_tarput
1759 will deal with the rest.
1761 static char * get_longfilename(file_info2 finfo)
1763 int namesize = finfo.size + strlen(cur_dir) + 2;
1764 char *longname = malloc(namesize);
1765 int offset = 0, left = finfo.size;
1766 BOOL first = True;
1768 DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
1769 DEBUG(5, ("Len = %i\n", finfo.size));
1771 if (longname == NULL) {
1773 DEBUG(0, ("could not allocate buffer of size %d for longname\n",
1774 finfo.size + strlen(cur_dir) + 2));
1775 return(NULL);
1778 /* First, add cur_dir to the long file name */
1780 if (strlen(cur_dir) > 0) {
1781 strncpy(longname, cur_dir, namesize);
1782 offset = strlen(cur_dir);
1785 /* Loop through the blocks picking up the name */
1787 while (left > 0) {
1789 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1791 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1792 return(NULL);
1796 unfixtarname(longname + offset, buffer_p, MIN(TBLOCK, finfo.size), first--);
1797 DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
1799 offset += TBLOCK;
1800 left -= TBLOCK;
1804 return(longname);
1808 static void do_tarput(void)
1810 file_info2 finfo;
1811 struct timeval tp_start;
1812 char *inbuf, *outbuf, *longfilename = NULL, linkflag;
1813 int skip = False;
1815 GetTimeOfDay(&tp_start);
1817 DEBUG(5, ("RJS do_tarput called ...\n"));
1819 buffer_p = tarbuf + tbufsiz; /* init this to force first read */
1821 #if 0 /* Fix later ... */
1822 if (push_dir(&dir_stack, &finfo)) {
1823 file_info2 *finfo2;
1825 finfo2 = pop_dir(&dir_stack);
1826 inbuf = top_dir_name(&dir_stack); /* FIXME */
1827 if (sub_dir(inbuf, finfo2 -> name)){
1829 DEBUG(0, (""));
1833 #endif
1835 inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1836 outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1838 if (!inbuf || !outbuf) {
1840 DEBUG(0, ("Out of memory during allocate of inbuf and outbuf!\n"));
1841 return;
1845 /* Now read through those files ... */
1847 while (True) {
1849 /* Get us to the next block, or the first block first time around */
1851 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1853 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1855 return;
1859 DEBUG(5, ("Reading the next header ...\n"));
1861 switch (readtarheader((union hblock *) buffer_p, &finfo, cur_dir)) {
1863 case -2: /* Hmm, not good, but not fatal */
1864 DEBUG(0, ("Skipping %s...\n", finfo.name));
1865 if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) &&
1866 !skip_file(finfo.size)) {
1868 DEBUG(0, ("Short file, bailing out...\n"));
1869 free(inbuf); free(outbuf);
1870 return;
1874 break;
1876 case -1:
1877 DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
1878 free(inbuf); free(outbuf);
1879 return;
1881 case 0: /* chksum is zero - looks like an EOF */
1882 DEBUG(0, ("total of %d tar files restored to share\n", ntarf));
1883 free(inbuf); free(outbuf);
1884 return; /* Hmmm, bad here ... */
1886 default:
1887 /* No action */
1889 break;
1893 /* Now, do we have a long file name? */
1895 if (longfilename != NULL) {
1897 free(finfo.name); /* Free the space already allocated */
1898 finfo.name = longfilename;
1899 longfilename = NULL;
1903 /* Well, now we have a header, process the file ... */
1905 /* Should we skip the file? We have the long name as well here */
1907 skip = clipn &&
1908 ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl)
1909 #ifdef HAVE_REGEX_H
1910 || (tar_re_search && !regexec(preg, finfo.name, 0, NULL, 0)));
1911 #else
1912 || (tar_re_search && mask_match(finfo.name, cliplist[0], True, False)));
1913 #endif
1915 DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
1917 if (skip) {
1919 skip_file(finfo.size);
1920 continue;
1924 /* We only get this far if we should process the file */
1925 linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
1927 switch (linkflag) {
1929 case '0': /* Should use symbolic names--FIXME */
1931 /* Skip to the next block first, so we can get the file, FIXME, should
1932 be in get_file ... */
1934 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1935 DEBUG(0, ("Short file, bailing out...\n"));
1936 free(inbuf); free(outbuf);
1937 return;
1939 if (!get_file(finfo, inbuf, outbuf)) {
1941 free(inbuf); free(outbuf);
1942 DEBUG(0, ("Abandoning restore\n"));
1943 return;
1946 break;
1948 case '5':
1949 if (!get_dir(finfo, inbuf, outbuf)) {
1950 free(inbuf); free(outbuf);
1951 DEBUG(0, ("Abandoning restore \n"));
1952 return;
1954 break;
1956 case 'L':
1957 longfilename = get_longfilename(finfo);
1958 if (!longfilename) {
1959 free(inbuf); free(outbuf);
1960 DEBUG(0, ("abandoning restore\n"));
1961 return;
1964 DEBUG(5, ("Long file name: %s\n", longfilename));
1965 break;
1967 default:
1968 skip_file(finfo.size); /* Don't handle these yet */
1969 break;
1978 #else
1980 static void do_tarput()
1982 file_info2 finfo;
1983 int nread=0, bufread;
1984 char *inbuf,*outbuf, *longname = NULL;
1985 int fsize=0;
1986 int fnum;
1987 struct timeval tp_start;
1988 BOOL tskip=False; /* We'll take each file as it comes */
1990 finfo.name = NULL; /* No name in here ... */
1992 GetTimeOfDay(&tp_start);
1994 inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1995 outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1997 if (!inbuf || !outbuf)
1999 DEBUG(0,("out of memory\n"));
2000 return;
2004 * Must read in tbufsiz dollops
2007 /* These should be the only reads in clitar.c */
2008 while ((bufread=read(tarhandle, tarbuf, tbufsiz))>0) {
2009 char *endofbuffer;
2010 int chunk;
2012 /* Code to handle a short read.
2013 * We always need a TBLOCK full of stuff
2015 if (bufread % TBLOCK) {
2016 int lchunk=TBLOCK-(bufread % TBLOCK);
2017 int lread;
2019 /* It's a shorty - a short read that is */
2020 DEBUG(3, ("Short read, read %d so far (need %d)\n", bufread, lchunk));
2022 while ((lread=read(tarhandle, tarbuf+bufread, lchunk))>0) {
2023 bufread+=lread;
2024 if (!(lchunk-=lread)) break;
2027 /* If we've reached EOF then that must be a short file */
2028 if (lread<=0) break;
2031 buffer_p=tarbuf;
2032 endofbuffer=tarbuf+bufread;
2034 if (tskip) {
2035 if (fsize<bufread) {
2036 tskip=False;
2037 buffer_p+=fsize;
2038 fsize=0;
2039 } else {
2040 if (fsize==bufread) tskip=False;
2041 fsize-=bufread;
2042 continue;
2046 do {
2047 if (!fsize)
2049 int next_header = 1; /* Want at least one header */
2050 while (next_header)
2052 if (buffer_p >= endofbuffer) {
2054 bufread = read(tarhandle, tarbuf, tbufsiz);
2055 buffer_p = tarbuf;
2058 next_header = 0; /* Don't want the next one ... */
2060 if (finfo.name != NULL) { /* Free the space */
2062 free(finfo.name);
2063 finfo.name = NULL;
2066 DEBUG(5, ("Tarbuf=%X, buffer=%X, endofbuf=%X\n",
2067 (int)tarbuf, (int)buffer_p, (int)endofbuffer));
2068 switch (readtarheader((union hblock *) buffer_p, &finfo, cur_dir))
2070 case -2: /* something dodgy but not fatal about this */
2071 DEBUG(0, ("skipping %s...\n", finfo.name));
2072 buffer_p+=TBLOCK; /* header - like a link */
2073 continue;
2074 case -1:
2075 DEBUG(0, ("abandoning restore, -1 from readtarheader\n"));
2076 free(inbuf); free(outbuf);
2077 return;
2078 case 0: /* chksum is zero - we assume that one all zero
2079 *header block will do for eof */
2080 DEBUG(0,
2081 ("total of %d tar files restored to share\n", ntarf));
2082 free(inbuf); free(outbuf);
2083 return;
2084 default:
2085 break;
2088 /* If we have a longname left from the last time through,
2089 copy it into finfo.name and free it.
2091 The size of a pstring is the limiting factor on filenames
2092 and directory names now. The total pathname length must be
2093 less than sizeof(pstring) - 1, which is currently 1023. */
2095 if (longname != NULL) {
2097 free(finfo.name); /* Free the name in the finfo */
2098 finfo.name = string_create_s(strlen(longname) + 2);
2099 strncpy(finfo.name, longname, strlen(longname) + 1);
2100 DEBUG(5, ("Long name = \"%s\", filename=\"%s\"\n", longname, finfo.name));
2101 free(longname);
2102 longname = NULL;
2106 /* Check if a long-link. We do this before the clip checking
2107 because clip-checking should clip on real name - RJS */
2109 if (((union hblock *)buffer_p) -> dbuf.linkflag == 'L') {
2110 int file_len, first = 0; char *cp;
2112 /* Skip this header, but pick up length, get the name and
2113 fix the name and skip the name. Hmmm, what about end of
2114 buffer??? */
2116 longname = malloc(finfo.size + strlen(cur_dir) + 1);
2117 if (longname == NULL) {
2119 DEBUG(0, ("could not allocate buffer of size %d for longname\n",
2120 finfo.size + strlen(cur_dir) + 1)
2122 free(inbuf); free(outbuf);
2123 return;
2127 bzero(longname, finfo.size + strlen(cur_dir) +1);
2129 buffer_p += TBLOCK; /* Skip that longlink header */
2131 /* This needs restructuring ... */
2133 safe_strcpy(longname, cur_dir, strlen(cur_dir) + 1);
2134 cp = longname + strlen(cur_dir);
2135 file_len = finfo.size;
2137 DEBUG(5, ("longname=%0X, cp=%0X, file_len=%i\n",
2138 (int)longname, (int)cp, file_len));
2140 while (file_len > 0) {
2142 if (buffer_p >= endofbuffer) {
2144 bufread = read(tarhandle, tarbuf, tbufsiz);
2146 buffer_p = tarbuf;
2150 unfixtarname(cp, buffer_p, file_len >= TBLOCK?TBLOCK:file_len, first == 0);
2152 first++; /* Not the first anymore */
2153 cp = cp + strlen(cp); /* Move to end of string */
2154 buffer_p += TBLOCK;
2155 file_len -= TBLOCK;
2156 DEBUG(5, ("cp=%0X, file_len=%i\n", (int)cp, file_len));
2157 next_header = 1; /* Force read of next header */
2162 tskip=clipn
2163 && ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl)
2164 #ifdef HAVE_REGEX_H
2165 || (tar_re_search && !regexec(preg, finfo.name, 0, NULL, 0)));
2166 #else
2167 || (tar_re_search && mask_match(finfo.name, cliplist[0], True, False)));
2168 #endif
2169 if (tskip) {
2170 buffer_p+=TBLOCK;
2171 if (finfo.mode & aDIR)
2172 continue;
2173 else if ((fsize=finfo.size) % TBLOCK) {
2174 fsize+=TBLOCK-(fsize%TBLOCK);
2176 if (fsize<endofbuffer-buffer_p) {
2177 buffer_p+=fsize;
2178 fsize=0;
2179 continue;
2180 } else {
2181 fsize-=endofbuffer-buffer_p;
2182 break;
2186 DEBUG(5, ("do_tarput: File is: %s\n", finfo.name));
2188 if (finfo.mode & aDIR)
2191 DEBUG(5, ("Creating directory: %s\n", finfo.name));
2192 DEBUG(0, ("restore tar dir %s of size %d bytes\n",
2193 finfo.name, finfo.size));
2195 if (!ensurepath(finfo.name, inbuf, outbuf))
2197 DEBUG(0, ("abandoning restore, problems ensuring path\n"));
2198 free(inbuf); free(outbuf);
2199 return;
2201 else
2203 /* Now we update the creation date ... */
2205 DEBUG(5, ("Updating creation date on %s\n", finfo.name));
2207 if (!do_setrtime(finfo.name, finfo.mtime, True)) {
2209 if (tar_real_noisy) {
2210 DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
2212 /*return; - Win 95 does not like setting time on dirs */
2216 ntarf++;
2217 buffer_p+=TBLOCK;
2218 continue;
2222 fsize=finfo.size;
2224 if (ensurepath(finfo.name, inbuf, outbuf)
2225 && !smbcreat(finfo, &fnum, inbuf, outbuf))
2227 DEBUG(0, ("abandoning restore\n"));
2228 free(inbuf);free(outbuf);
2229 return;
2232 DEBUG(0 ,("restore tar file %s of size %d bytes\n",
2233 finfo.name, finfo.size));
2235 /* if (!finfo.size) {
2236 if (!smbshut(finfo, fnum, inbuf, outbuf)){
2237 DEBUG(0, ("Error closing remote file of length 0: %s\n", finfo.name));
2238 free(inbuf);free(outbuf);
2239 return;
2241 } */
2243 nread=0;
2244 if ((buffer_p+=TBLOCK) >= endofbuffer) break;
2245 } /* if (!fsize) */
2247 /* write out the file in chunk sized chunks - don't
2248 * go past end of buffer though */
2249 chunk=(fsize-nread < endofbuffer - buffer_p)
2250 ? fsize - nread : endofbuffer - buffer_p;
2252 while (chunk > 0) {
2253 int minichunk=MIN(chunk, max_xmit-200);
2255 if (!smbwrite(fnum, /* file descriptor */
2256 minichunk, /* n */
2257 nread, /* offset low */
2258 0, /* offset high - not implemented */
2259 fsize-nread, /* left - only hint to server */
2260 buffer_p,
2261 inbuf,
2262 outbuf))
2264 DEBUG(0, ("Error writing remote file\n"));
2265 free(inbuf); free(outbuf);
2266 return;
2268 DEBUG(5, ("chunk writing fname=%s fnum=%d nread=%d minichunk=%d chunk=%d size=%d\n", finfo.name, fnum, nread, minichunk, chunk, fsize));
2270 buffer_p+=minichunk; nread+=minichunk;
2271 chunk-=minichunk;
2274 if (nread>=fsize)
2276 if (!smbshut(finfo, fnum, inbuf, outbuf))
2278 DEBUG(0, ("Error closing remote file\n"));
2279 free(inbuf);free(outbuf);
2280 return;
2282 if (fsize % TBLOCK) buffer_p+=TBLOCK - (fsize % TBLOCK);
2283 DEBUG(5, ("buffer_p is now %d (psn=%d)\n",
2284 (int) buffer_p, (int)(buffer_p - tarbuf)));
2285 ntarf++;
2286 fsize=0;
2289 } while (buffer_p < endofbuffer);
2292 DEBUG(0, ("premature eof on tar file ?\n"));
2293 DEBUG(0,("total of %d tar files restored to share\n", ntarf));
2295 free(inbuf); free(outbuf);
2297 #endif
2300 * samba interactive commands
2303 /****************************************************************************
2304 Blocksize command
2305 ***************************************************************************/
2306 void cmd_block(char *dum_in, char *dum_out)
2308 fstring buf;
2309 int block;
2311 if (!next_token(NULL,buf,NULL,sizeof(buf)))
2313 DEBUG(0, ("blocksize <n>\n"));
2314 return;
2317 block=atoi(buf);
2318 if (block < 0 || block > 65535)
2320 DEBUG(0, ("blocksize out of range"));
2321 return;
2324 blocksize=block;
2325 DEBUG(2,("blocksize is now %d\n", blocksize));
2328 /****************************************************************************
2329 command to set incremental / reset mode
2330 ***************************************************************************/
2331 void cmd_tarmode(char *dum_in, char *dum_out)
2333 fstring buf;
2335 while (next_token(NULL,buf,NULL,sizeof(buf))) {
2336 if (strequal(buf, "full"))
2337 tar_inc=False;
2338 else if (strequal(buf, "inc"))
2339 tar_inc=True;
2340 else if (strequal(buf, "reset"))
2341 tar_reset=True;
2342 else if (strequal(buf, "noreset"))
2343 tar_reset=False;
2344 else if (strequal(buf, "system"))
2345 tar_system=True;
2346 else if (strequal(buf, "nosystem"))
2347 tar_system=False;
2348 else if (strequal(buf, "hidden"))
2349 tar_hidden=True;
2350 else if (strequal(buf, "nohidden"))
2351 tar_hidden=False;
2352 else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
2353 tar_noisy=True;
2354 else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
2355 tar_noisy=False;
2356 else DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
2359 DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
2360 tar_inc ? "incremental" : "full",
2361 tar_system ? "system" : "nosystem",
2362 tar_hidden ? "hidden" : "nohidden",
2363 tar_reset ? "reset" : "noreset",
2364 tar_noisy ? "verbose" : "quiet"));
2368 /****************************************************************************
2369 Feeble attrib command
2370 ***************************************************************************/
2371 void cmd_setmode(char *dum_in, char *dum_out)
2373 char *q;
2374 fstring buf;
2375 pstring fname;
2376 int attra[2];
2377 int direct=1;
2379 attra[0] = attra[1] = 0;
2381 if (!next_token(NULL,buf,NULL,sizeof(buf)))
2383 DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
2384 return;
2387 safe_strcpy(fname, cur_dir, sizeof(pstring));
2388 safe_strcat(fname, buf, sizeof(pstring));
2390 while (next_token(NULL,buf,NULL,sizeof(buf))) {
2391 q=buf;
2393 while(*q)
2394 switch (*q++) {
2395 case '+': direct=1;
2396 break;
2397 case '-': direct=0;
2398 break;
2399 case 'r': attra[direct]|=aRONLY;
2400 break;
2401 case 'h': attra[direct]|=aHIDDEN;
2402 break;
2403 case 's': attra[direct]|=aSYSTEM;
2404 break;
2405 case 'a': attra[direct]|=aARCH;
2406 break;
2407 default: DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
2408 return;
2412 if (attra[ATTRSET]==0 && attra[ATTRRESET]==0)
2414 DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
2415 return;
2418 DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
2419 (void) do_setrattr(fname, attra[ATTRSET], ATTRSET);
2420 (void) do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
2423 /****************************************************************************
2424 Principal command for creating / extracting
2425 ***************************************************************************/
2426 void cmd_tar(char *inbuf, char *outbuf)
2428 fstring buf;
2429 char **argl;
2430 int argcl;
2432 if (!next_token(NULL,buf,NULL,sizeof(buf)))
2434 DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
2435 return;
2438 argl=toktocliplist(&argcl, NULL);
2439 if (!tar_parseargs(argcl, argl, buf, 0))
2440 return;
2442 process_tar(inbuf, outbuf);
2444 free(argl);
2447 /****************************************************************************
2448 Command line (option) version
2449 ***************************************************************************/
2450 int process_tar(char *inbuf, char *outbuf)
2452 initarbuf();
2453 switch(tar_type) {
2454 case 'x':
2456 #if 0
2457 do_tarput2();
2458 #else
2459 do_tarput();
2460 #endif
2461 free(tarbuf);
2462 close(tarhandle);
2463 break;
2464 case 'r':
2465 case 'c':
2466 if (clipn && tar_excl) {
2467 int i;
2468 pstring tarmac;
2470 for (i=0; i<clipn; i++) {
2471 DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
2473 if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
2474 *(cliplist[i]+strlen(cliplist[i])-1)='\0';
2477 if (strrchr(cliplist[i], '\\')) {
2478 pstring saved_dir;
2480 safe_strcpy(saved_dir, cur_dir, sizeof(pstring));
2482 if (*cliplist[i]=='\\') {
2483 safe_strcpy(tarmac, cliplist[i], sizeof(pstring));
2484 } else {
2485 safe_strcpy(tarmac, cur_dir, sizeof(pstring));
2486 safe_strcat(tarmac, cliplist[i], sizeof(pstring));
2488 safe_strcpy(cur_dir, tarmac, sizeof(pstring));
2489 *(strrchr(cur_dir, '\\')+1)='\0';
2491 do_dir((char *)inbuf,(char *)outbuf,tarmac,attribute,do_tar,recurse, True);
2492 safe_strcpy(cur_dir,saved_dir, sizeof(pstring));
2493 } else {
2494 safe_strcpy(tarmac, cur_dir, sizeof(pstring));
2495 safe_strcat(tarmac, cliplist[i], sizeof(pstring));
2496 do_dir((char *)inbuf,(char *)outbuf,tarmac,attribute,do_tar,recurse, True);
2499 } else {
2500 pstring mask;
2501 safe_strcpy(mask,cur_dir, sizeof(pstring));
2502 safe_strcat(mask,"\\*", sizeof(pstring));
2503 do_dir((char *)inbuf,(char *)outbuf,mask,attribute,do_tar,recurse, True);
2506 if (ntarf) dotareof(tarhandle);
2507 close(tarhandle);
2508 free(tarbuf);
2510 DEBUG(0, ("tar: dumped %d tar files\n", ntarf));
2511 DEBUG(0, ("Total bytes written: %d\n", ttarf));
2512 break;
2515 if (must_free_cliplist) {
2516 int i;
2517 for (i = 0; i < clipn; ++i) {
2518 free(cliplist[i]);
2520 free(cliplist);
2521 cliplist = NULL;
2522 clipn = 0;
2523 must_free_cliplist = False;
2526 return(0);
2529 /****************************************************************************
2530 Find a token (filename) in a clip list
2531 ***************************************************************************/
2532 static int clipfind(char **aret, int ret, char *tok)
2534 if (aret==NULL) return 0;
2536 /* ignore leading slashes or dots in token */
2537 while(strchr("/\\.", *tok)) tok++;
2539 while(ret--) {
2540 char *pkey=*aret++;
2542 /* ignore leading slashes or dots in list */
2543 while(strchr("/\\.", *pkey)) pkey++;
2545 if (!strslashcmp(pkey, tok)) return 1;
2548 return 0;
2551 /****************************************************************************
2552 Read list of files to include from the file and initialize cliplist
2553 accordingly.
2554 ***************************************************************************/
2555 static int read_inclusion_file(char *filename)
2557 FILE *inclusion = NULL;
2558 char buf[MAXPATHLEN + 1];
2559 char *inclusion_buffer = NULL;
2560 int inclusion_buffer_size = 0;
2561 int inclusion_buffer_sofar = 0;
2562 char *p;
2563 char *tmpstr;
2564 int i;
2565 int error = 0;
2567 clipn = 0;
2568 buf[MAXPATHLEN] = '\0'; /* guarantee null-termination */
2569 if ((inclusion = fopen(filename, "r")) == NULL) {
2570 /* XXX It would be better to include a reason for failure, but without
2571 * autoconf, it's hard to use strerror, sys_errlist, etc.
2573 DEBUG(0,("Unable to open inclusion file %s\n", filename));
2574 return 0;
2577 while ((! error) && (fgets(buf, sizeof(buf)-1, inclusion))) {
2578 if (inclusion_buffer == NULL) {
2579 inclusion_buffer_size = 1024;
2580 if ((inclusion_buffer = malloc(inclusion_buffer_size)) == NULL) {
2581 DEBUG(0,("failure allocating buffer to read inclusion file\n"));
2582 error = 1;
2583 break;
2587 if (buf[strlen(buf)-1] == '\n') {
2588 buf[strlen(buf)-1] = '\0';
2591 if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
2592 inclusion_buffer_size *= 2;
2593 inclusion_buffer = Realloc(inclusion_buffer,inclusion_buffer_size);
2594 if (! inclusion_buffer) {
2595 DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
2596 inclusion_buffer_size));
2597 error = 1;
2598 break;
2602 safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
2603 inclusion_buffer_sofar += strlen(buf) + 1;
2604 clipn++;
2606 fclose(inclusion);
2608 if (! error) {
2609 /* Allocate an array of clipn + 1 char*'s for cliplist */
2610 cliplist = malloc((clipn + 1) * sizeof(char *));
2611 if (cliplist == NULL) {
2612 DEBUG(0,("failure allocating memory for cliplist\n"));
2613 error = 1;
2614 } else {
2615 cliplist[clipn] = NULL;
2616 p = inclusion_buffer;
2617 for (i = 0; (! error) && (i < clipn); i++) {
2618 /* set current item to NULL so array will be null-terminated even if
2619 * malloc fails below. */
2620 cliplist[i] = NULL;
2621 if ((tmpstr = (char *)malloc(strlen(p)+1)) == NULL) {
2622 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
2623 error = 1;
2624 } else {
2625 unfixtarname(tmpstr, p, strlen(p) + 1, True);
2626 cliplist[i] = tmpstr;
2627 if ((p = strchr(p, '\000')) == NULL) {
2628 DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
2629 abort();
2632 ++p;
2634 must_free_cliplist = True;
2638 if (inclusion_buffer) {
2639 free(inclusion_buffer);
2641 if (error) {
2642 if (cliplist) {
2643 char **pp;
2644 /* We know cliplist is always null-terminated */
2645 for (pp = cliplist; *pp; ++pp) {
2646 free(*pp);
2648 free(cliplist);
2649 cliplist = NULL;
2650 must_free_cliplist = False;
2652 return 0;
2655 /* cliplist and its elements are freed at the end of process_tar. */
2656 return 1;
2659 /****************************************************************************
2660 Parse tar arguments. Sets tar_type, tar_excl, etc.
2661 ***************************************************************************/
2662 int tar_parseargs(int argc, char *argv[], char *Optarg, int Optind)
2664 char tar_clipfl='\0';
2666 /* Reset back to defaults - could be from interactive version
2667 * reset mode and archive mode left as they are though
2669 tar_type='\0';
2670 tar_excl=True;
2671 dry_run=False;
2673 while (*Optarg)
2674 switch(*Optarg++) {
2675 case 'c':
2676 tar_type='c';
2677 break;
2678 case 'x':
2679 if (tar_type=='c') {
2680 printf("Tar must be followed by only one of c or x.\n");
2681 return 0;
2683 tar_type='x';
2684 break;
2685 case 'b':
2686 if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
2687 DEBUG(0,("Option b must be followed by valid blocksize\n"));
2688 return 0;
2689 } else {
2690 Optind++;
2692 break;
2693 case 'g':
2694 tar_inc=True;
2695 break;
2696 case 'N':
2697 if (Optind>=argc) {
2698 DEBUG(0,("Option N must be followed by valid file name\n"));
2699 return 0;
2700 } else {
2701 SMB_STRUCT_STAT stbuf;
2702 extern time_t newer_than;
2704 if (dos_stat(argv[Optind], &stbuf) == 0) {
2705 newer_than = stbuf.st_mtime;
2706 DEBUG(1,("Getting files newer than %s",
2707 asctime(LocalTime(&newer_than))));
2708 Optind++;
2709 } else {
2710 DEBUG(0,("Error setting newer-than time\n"));
2711 return 0;
2714 break;
2715 case 'a':
2716 tar_reset=True;
2717 break;
2718 case 'q':
2719 tar_noisy=False;
2720 break;
2721 case 'I':
2722 if (tar_clipfl) {
2723 DEBUG(0,("Only one of I,X,F must be specified\n"));
2724 return 0;
2726 tar_clipfl='I';
2727 break;
2728 case 'X':
2729 if (tar_clipfl) {
2730 DEBUG(0,("Only one of I,X,F must be specified\n"));
2731 return 0;
2733 tar_clipfl='X';
2734 break;
2735 case 'F':
2736 if (tar_clipfl) {
2737 DEBUG(0,("Only one of I,X,F must be specified\n"));
2738 return 0;
2740 tar_clipfl='F';
2741 break;
2742 case 'r':
2743 DEBUG(0, ("tar_re_search set\n"));
2744 tar_re_search = True;
2745 break;
2746 case 'n':
2747 if (tar_type == 'c') {
2748 DEBUG(0, ("dry_run set\n"));
2749 dry_run = True;
2750 } else {
2751 DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
2752 return 0;
2754 break;
2755 default:
2756 DEBUG(0,("Unknown tar option\n"));
2757 return 0;
2760 if (!tar_type) {
2761 printf("Option T must be followed by one of c or x.\n");
2762 return 0;
2765 /* tar_excl is true if cliplist lists files to be included.
2766 * Both 'I' and 'F' mean include. */
2767 tar_excl=tar_clipfl!='X';
2769 if (tar_clipfl=='F') {
2770 if (argc-Optind-1 != 1) {
2771 DEBUG(0,("Option F must be followed by exactly one filename.\n"));
2772 return 0;
2774 if (! read_inclusion_file(argv[Optind+1])) {
2775 return 0;
2777 } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
2778 char *tmpstr;
2779 char **tmplist;
2780 int clipcount;
2782 cliplist=argv+Optind+1;
2783 clipn=argc-Optind-1;
2784 clipcount = clipn;
2786 if ((tmplist=malloc(clipn*sizeof(char *))) == NULL) {
2787 DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n",
2788 clipn)
2790 return 0;
2793 for (clipcount = 0; clipcount < clipn; clipcount++) {
2795 DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
2797 if ((tmpstr = (char *)malloc(strlen(cliplist[clipcount])+1)) == NULL) {
2798 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n",
2799 clipcount)
2801 return 0;
2803 unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
2804 tmplist[clipcount] = tmpstr;
2805 DEBUG(5, ("Processed an item, %s\n", tmpstr));
2807 DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
2809 cliplist = tmplist;
2810 must_free_cliplist = True;
2813 if (Optind+1<argc && tar_re_search) { /* Doing regular expression seaches */
2814 #ifdef HAVE_REGEX_H
2815 int errcode;
2817 if ((preg = (regex_t *)malloc(65536)) == NULL) {
2819 DEBUG(0, ("Could not allocate buffer for regular expression search\n"));
2820 return;
2824 if (errcode = regcomp(preg, argv[Optind + 1], REG_EXTENDED)) {
2825 char errstr[1024];
2826 size_t errlen;
2828 errlen = regerror(errcode, preg, errstr, sizeof(errstr) - 1);
2830 DEBUG(0, ("Could not compile pattern buffer for re search: %s\n%s\n", argv[Optind + 1], errstr));
2831 return;
2834 #endif
2836 clipn=argc-Optind-1;
2837 cliplist=argv+Optind+1;
2841 if (Optind>=argc || !strcmp(argv[Optind], "-")) {
2842 /* Sets tar handle to either 0 or 1, as appropriate */
2843 tarhandle=(tar_type=='c');
2844 } else {
2845 if (tar_type=='c' && (dry_run || strcmp(argv[Optind], "/dev/null")==0))
2847 if (!dry_run) {
2848 DEBUG(0,("Output is /dev/null, assuming dry_run"));
2849 dry_run = True;
2851 tarhandle=-1;
2852 } else
2853 if ((tar_type=='x' && (tarhandle = open(argv[Optind], O_RDONLY)) == -1)
2854 || (tar_type=='c' && (tarhandle=creat(argv[Optind], 0644)) < 0))
2856 DEBUG(0,("Error opening local file %s - %s\n",
2857 argv[Optind], strerror(errno)));
2858 return(0);
2862 return 1;