2 Unix SMB/CIFS implementation.
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 2 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, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 /* The following changes developed by Richard Sharpe for Canon Information
22 Systems Research Australia (CISRA)
24 1. Restore can now restore files with long file names
25 2. Save now saves directory information so that we can restore
26 directory creation times
27 3. tar now accepts both UNIX path names and DOS path names. I prefer
28 those lovely /'s to those UGLY \'s :-)
29 4. the files to exclude can be specified as a regular expression by adding
30 an r flag to the other tar flags. Eg:
32 -TcrX file.tar "*.(obj|exe)"
34 will skip all .obj and .exe files
40 #include "../client/client_proto.h"
42 static int clipfind(char **aret, int ret, char *tok);
43 void dos_clean_name(char *s);
45 typedef struct file_info_struct file_info2;
47 struct file_info_struct
53 /* These times are normally kept in GMT */
57 char *name; /* This is dynamically allocate */
59 file_info2 *next, *prev; /* Used in the stack ... */
70 #define SEPARATORS " \t\n\r"
71 extern struct cli_state *cli;
73 /* These defines are for the do_setrattr routine, to indicate
74 * setting and reseting of file attributes in the function call */
78 static uint16 attribute = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
80 #ifndef CLIENT_TIMEOUT
81 #define CLIENT_TIMEOUT (30*1000)
84 static char *tarbuf, *buffer_p;
85 static int tp, ntarf, tbufsiz;
87 /* Incremental mode */
88 static BOOL tar_inc=False;
89 /* Reset archive bit */
90 static BOOL tar_reset=False;
91 /* Include / exclude mode (true=include, false=exclude) */
92 static BOOL tar_excl=True;
93 /* use regular expressions for search on file names */
94 static BOOL tar_re_search=False;
98 /* Do not dump anything, just calculate sizes */
99 static BOOL dry_run=False;
100 /* Dump files with System attribute */
101 static BOOL tar_system=True;
102 /* Dump files with Hidden attribute */
103 static BOOL tar_hidden=True;
104 /* Be noisy - make a catalogue */
105 static BOOL tar_noisy=True;
106 static BOOL tar_real_noisy=False; /* Don't want to be really noisy by default */
109 static char **cliplist=NULL;
111 static BOOL must_free_cliplist = False;
113 extern file_info def_finfo;
114 extern BOOL lowercase;
116 extern BOOL readbraw_supported;
118 extern pstring cur_dir;
119 extern int get_total_time_ms;
120 extern int get_total_size;
122 static int blocksize=20;
123 static int tarhandle;
125 static void writetarheader(int f, const char *aname, SMB_BIG_UINT size, time_t mtime,
126 const char *amode, unsigned char ftype);
127 static void do_atar(char *rname,char *lname,file_info *finfo1);
128 static void do_tar(file_info *finfo);
129 static void oct_it(SMB_BIG_UINT value, int ndgs, char *p);
130 static void fixtarname(char *tptr, const char *fp, int l);
131 static int dotarbuf(int f, char *b, int n);
132 static void dozerobuf(int f, int n);
133 static void dotareof(int f);
134 static void initarbuf(void);
136 /* restore functions */
137 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix);
138 static long unoct(char *p, int ndgs);
139 static void do_tarput(void);
140 static void unfixtarname(char *tptr, char *fp, int l, BOOL first);
143 * tar specific utitlities
146 /*******************************************************************
147 Create a string of size size+1 (for the null)
148 *******************************************************************/
149 static char *string_create_s(int size)
153 tmp = (char *)malloc(size+1);
157 DEBUG(0, ("Out of memory in string_create_s\n"));
165 /****************************************************************************
166 Write a tar header to buffer
167 ****************************************************************************/
168 static void writetarheader(int f, const char *aname, SMB_BIG_UINT size, time_t mtime,
169 const char *amode, unsigned char ftype)
175 DEBUG(5, ("WriteTarHdr, Type = %c, Size= %.0f, Name = %s\n", ftype, (double)size, aname));
177 memset(hb.dummy, 0, sizeof(hb.dummy));
180 if (l >= NAMSIZ - 1) {
181 /* write a GNU tar style long header */
183 b = (char *)malloc(l+TBLOCK+100);
185 DEBUG(0,("out of memory\n"));
188 writetarheader(f, "/./@LongLink", l+2, 0, " 0 \0", 'L');
189 memset(b, 0, l+TBLOCK+100);
190 fixtarname(b, aname, l);
192 DEBUG(5, ("File name in tar file: %s, size=%d, \n", b, (int)strlen(b)));
193 dotarbuf(f, b, TBLOCK*(((i-1)/TBLOCK)+1));
197 /* use l + 1 to do the null too */
198 fixtarname(hb.dbuf.name, aname, (l >= NAMSIZ) ? NAMSIZ : l + 1);
201 strlower(hb.dbuf.name);
203 /* write out a "standard" tar format header */
205 hb.dbuf.name[NAMSIZ-1]='\0';
206 safe_strcpy(hb.dbuf.mode, amode, strlen(amode));
207 oct_it((SMB_BIG_UINT)0, 8, hb.dbuf.uid);
208 oct_it((SMB_BIG_UINT)0, 8, hb.dbuf.gid);
209 oct_it((SMB_BIG_UINT) size, 13, hb.dbuf.size);
210 oct_it((SMB_BIG_UINT) mtime, 13, hb.dbuf.mtime);
211 memcpy(hb.dbuf.chksum, " ", sizeof(hb.dbuf.chksum));
212 memset(hb.dbuf.linkname, 0, NAMSIZ);
213 hb.dbuf.linkflag=ftype;
215 for (chk=0, i=sizeof(hb.dummy), jp=hb.dummy; --i>=0;) chk+=(0xFF & *jp++);
217 oct_it((SMB_BIG_UINT) chk, 8, hb.dbuf.chksum);
218 hb.dbuf.chksum[6] = '\0';
220 (void) dotarbuf(f, hb.dummy, sizeof(hb.dummy));
223 /****************************************************************************
224 Read a tar header into a hblock structure, and validate
225 ***************************************************************************/
226 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix)
233 * read in a "standard" tar format header - we're not that interested
234 * in that many fields, though
237 /* check the checksum */
238 for (chk=0, i=sizeof(hb->dummy), jp=hb->dummy; --i>=0;) chk+=(0xFF & *jp++);
243 /* compensate for blanks in chksum header */
244 for (i=sizeof(hb->dbuf.chksum), jp=hb->dbuf.chksum; --i>=0;)
247 chk += ' ' * sizeof(hb->dbuf.chksum);
249 fchk=unoct(hb->dbuf.chksum, sizeof(hb->dbuf.chksum));
251 DEBUG(5, ("checksum totals chk=%ld fchk=%ld chksum=%s\n",
252 chk, fchk, hb->dbuf.chksum));
256 DEBUG(0, ("checksums don't match %ld %ld\n", fchk, chk));
257 dump_data(5, (char *)hb - TBLOCK, TBLOCK *3);
261 if ((finfo->name = string_create_s(strlen(prefix) + strlen(hb -> dbuf.name) + 3)) == NULL) {
263 DEBUG(0, ("Out of space creating file_info2 for %s\n", hb -> dbuf.name));
268 safe_strcpy(finfo->name, prefix, strlen(prefix) + strlen(hb -> dbuf.name) + 3);
270 /* use l + 1 to do the null too; do prefix - prefcnt to zap leading slash */
271 unfixtarname(finfo->name + strlen(prefix), hb->dbuf.name,
272 strlen(hb->dbuf.name) + 1, True);
274 /* can't handle some links at present */
275 if ((hb->dbuf.linkflag != '0') && (hb -> dbuf.linkflag != '5')) {
276 if (hb->dbuf.linkflag == 0) {
277 DEBUG(6, ("Warning: NULL link flag (gnu tar archive ?) %s\n",
280 if (hb -> dbuf.linkflag == 'L') { /* We have a longlink */
281 /* Do nothing here at the moment. do_tarput will handle this
282 as long as the longlink gets back to it, as it has to advance
283 the buffer pointer, etc */
286 DEBUG(0, ("this tar file appears to contain some kind of link other than a GNUtar Longlink - ignoring\n"));
292 if ((unoct(hb->dbuf.mode, sizeof(hb->dbuf.mode)) & S_IFDIR)
293 || (*(finfo->name+strlen(finfo->name)-1) == '\\'))
295 finfo->mode=FILE_ATTRIBUTE_DIRECTORY;
298 finfo->mode=0; /* we don't care about mode at the moment, we'll
299 * just make it a regular file */
301 * Bug fix by richard@sj.co.uk
303 * REC: restore times correctly (as does tar)
304 * We only get the modification time of the file; set the creation time
305 * from the mod. time, and the access time to current time
307 finfo->mtime = finfo->ctime = strtol(hb->dbuf.mtime, NULL, 8);
308 finfo->atime = time(NULL);
309 finfo->size = unoct(hb->dbuf.size, sizeof(hb->dbuf.size));
314 /****************************************************************************
315 Write out the tar buffer to tape or wherever
316 ****************************************************************************/
317 static int dotarbuf(int f, char *b, int n)
324 /* This routine and the next one should be the only ones that do write()s */
325 if (tp + n >= tbufsiz)
330 memcpy(tarbuf + tp, b, diff);
331 fail=fail && (1+write(f, tarbuf, tbufsiz));
338 fail=fail && (1 + write(f, b, tbufsiz));
344 memcpy(tarbuf+tp, b, n);
348 return(fail ? writ : 0);
351 /****************************************************************************
352 Write zeros to buffer / tape
353 ****************************************************************************/
354 static void dozerobuf(int f, int n)
356 /* short routine just to write out n zeros to buffer -
357 * used to round files to nearest block
358 * and to do tar EOFs */
365 memset(tarbuf+tp, 0, tbufsiz-tp);
367 write(f, tarbuf, tbufsiz);
368 memset(tarbuf, 0, (tp+=n-tbufsiz));
372 memset(tarbuf+tp, 0, n);
377 /****************************************************************************
379 ****************************************************************************/
380 static void initarbuf(void)
382 /* initialize tar buffer */
383 tbufsiz=blocksize*TBLOCK;
384 tarbuf=malloc(tbufsiz); /* FIXME: We might not get the buffer */
386 /* reset tar buffer pointer and tar file counter and total dumped */
387 tp=0; ntarf=0; ttarf=0;
390 /****************************************************************************
391 Write two zero blocks at end of file
392 ****************************************************************************/
393 static void dotareof(int f)
395 SMB_STRUCT_STAT stbuf;
396 /* Two zero blocks at end of file, write out full buffer */
401 (void) dozerobuf(f, TBLOCK);
402 (void) dozerobuf(f, TBLOCK);
404 if (sys_fstat(f, &stbuf) == -1)
406 DEBUG(0, ("Couldn't stat file handle\n"));
410 /* Could be a pipe, in which case S_ISREG should fail,
411 * and we should write out at full size */
412 if (tp > 0) write(f, tarbuf, S_ISREG(stbuf.st_mode) ? tp : tbufsiz);
415 /****************************************************************************
416 (Un)mangle DOS pathname, make nonabsolute
417 ****************************************************************************/
418 static void fixtarname(char *tptr, const char *fp, int l)
420 /* add a '.' to start of file name, convert from ugly dos \'s in path
421 * to lovely unix /'s :-} */
424 safe_strcpy(tptr, fp, l);
425 string_replace(tptr, '\\', '/');
428 /****************************************************************************
429 Convert from decimal to octal string
430 ****************************************************************************/
431 static void oct_it (SMB_BIG_UINT value, int ndgs, char *p)
433 /* Converts long to octal string, pads with leading zeros */
435 /* skip final null, but do final space */
439 /* Loop does at least one digit */
441 p[--ndgs] = '0' + (char) (value & 7);
444 while (ndgs > 0 && value != 0);
446 /* Do leading zeros */
451 /****************************************************************************
452 Convert from octal string to long
453 ***************************************************************************/
454 static long unoct(char *p, int ndgs)
457 /* Converts octal string to long, ignoring any non-digit */
461 if (isdigit((int)*p))
462 value = (value << 3) | (long) (*p - '0');
470 /****************************************************************************
471 Compare two strings in a slash insensitive way, allowing s1 to match s2
472 if s1 is an "initial" string (up to directory marker). Thus, if s2 is
473 a file in any subdirectory of s1, declare a match.
474 ***************************************************************************/
475 static int strslashcmp(char *s1, char *s2)
481 || tolower(*s1) == tolower(*s2)
482 || (*s1 == '\\' && *s2=='/')
483 || (*s1 == '/' && *s2=='\\'))) {
487 /* if s1 has a trailing slash, it compared equal, so s1 is an "initial"
490 if (!*s1 && s1 != s1_0 && (*(s1-1) == '/' || *(s1-1) == '\\')) return 0;
492 /* ignore trailing slash on s1 */
493 if (!*s2 && (*s1 == '/' || *s1 == '\\') && !*(s1+1)) return 0;
495 /* check for s1 is an "initial" string of s2 */
496 if ((*s2 == '/' || *s2 == '\\') && !*s1) return 0;
502 /****************************************************************************
503 Ensure a remote path exists (make if necessary)
504 ***************************************************************************/
505 static BOOL ensurepath(char *fname)
507 /* *must* be called with buffer ready malloc'ed */
508 /* ensures path exists */
510 char *partpath, *ffname;
511 char *p=fname, *basehack;
513 DEBUG(5, ( "Ensurepath called with: %s\n", fname));
515 partpath = string_create_s(strlen(fname));
516 ffname = string_create_s(strlen(fname));
518 if ((partpath == NULL) || (ffname == NULL)){
520 DEBUG(0, ("Out of memory in ensurepath: %s\n", fname));
527 /* fname copied to ffname so can strtok */
529 safe_strcpy(ffname, fname, strlen(fname));
531 /* do a `basename' on ffname, so don't try and make file name directory */
532 if ((basehack=strrchr_m(ffname, '\\')) == NULL)
537 p=strtok(ffname, "\\");
541 safe_strcat(partpath, p, strlen(fname) + 1);
543 if (!cli_chkpath(cli, partpath)) {
544 if (!cli_mkdir(cli, partpath))
546 DEBUG(0, ("Error mkdirhiering\n"));
550 DEBUG(3, ("mkdirhiering %s\n", partpath));
554 safe_strcat(partpath, "\\", strlen(fname) + 1);
555 p = strtok(NULL,"/\\");
561 static int padit(char *buf, int bufsize, int padsize)
566 DEBUG(5, ("Padding with %d zeros\n", padsize));
567 memset(buf, 0, bufsize);
568 while( !berr && padsize > 0 ) {
569 bytestowrite= MIN(bufsize, padsize);
570 berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite;
571 padsize -= bytestowrite;
578 static void do_setrattr(char *name, uint16 attr, int set)
582 if (!cli_getatr(cli, name, &oldattr, NULL, NULL)) return;
584 if (set == ATTRSET) {
587 attr = oldattr & ~attr;
590 if (!cli_setatr(cli, name, attr, 0)) {
591 DEBUG(1,("setatr failed: %s\n", cli_errstr(cli)));
596 /****************************************************************************
597 append one remote file to the tar file
598 ***************************************************************************/
599 static void do_atar(char *rname,char *lname,file_info *finfo1)
602 SMB_BIG_UINT nread=0;
605 BOOL close_done = False;
606 BOOL shallitime=True;
608 int read_size = 65520;
611 struct timeval tp_start;
612 GetTimeOfDay(&tp_start);
614 ftype = '0'; /* An ordinary file ... */
617 finfo.size = finfo1 -> size;
618 finfo.mode = finfo1 -> mode;
619 finfo.uid = finfo1 -> uid;
620 finfo.gid = finfo1 -> gid;
621 finfo.mtime = finfo1 -> mtime;
622 finfo.atime = finfo1 -> atime;
623 finfo.ctime = finfo1 -> ctime;
624 finfo.name = finfo1 -> name;
627 finfo.size = def_finfo.size;
628 finfo.mode = def_finfo.mode;
629 finfo.uid = def_finfo.uid;
630 finfo.gid = def_finfo.gid;
631 finfo.mtime = def_finfo.mtime;
632 finfo.atime = def_finfo.atime;
633 finfo.ctime = def_finfo.ctime;
634 finfo.name = def_finfo.name;
639 DEBUG(3,("skipping file %s of size %12.0f bytes\n",
641 (double)finfo.size));
643 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
648 fnum = cli_open(cli, rname, O_RDONLY, DENY_NONE);
650 dos_clean_name(rname);
653 DEBUG(0,("%s opening remote file %s (%s)\n",
654 cli_errstr(cli),rname, cur_dir));
658 finfo.name = string_create_s(strlen(rname));
659 if (finfo.name == NULL) {
660 DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n"));
664 safe_strcpy(finfo.name,rname, strlen(rname));
667 if (!cli_getattrE(cli, fnum, &finfo.mode, &size, NULL, &finfo.atime, &finfo.mtime)) {
668 DEBUG(0, ("getattrE: %s\n", cli_errstr(cli)));
672 finfo.ctime = finfo.mtime;
675 DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
677 if (tar_inc && !(finfo.mode & FILE_ATTRIBUTE_ARCHIVE))
679 DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
682 else if (!tar_system && (finfo.mode & FILE_ATTRIBUTE_SYSTEM))
684 DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
687 else if (!tar_hidden && (finfo.mode & FILE_ATTRIBUTE_HIDDEN))
689 DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
694 DEBUG(3,("getting file %s of size %.0f bytes as a tar file %s",
699 /* write a tar header, don't bother with mode - just set to 100644 */
700 writetarheader(tarhandle, rname, finfo.size, finfo.mtime, "100644 \0", ftype);
702 while (nread < finfo.size && !close_done) {
704 DEBUG(3,("nread=%.0f\n",(double)nread));
706 datalen = cli_read(cli, fnum, data, nread, read_size);
709 DEBUG(0,("Error reading file %s : %s\n", rname, cli_errstr(cli)));
715 /* if file size has increased since we made file size query, truncate
716 read so tar header for this file will be correct.
719 if (nread > finfo.size) {
720 datalen -= nread - finfo.size;
721 DEBUG(0,("File size change - truncating %s to %.0f bytes\n", finfo.name, (double)finfo.size));
724 /* add received bits of file to buffer - dotarbuf will
725 * write out in 512 byte intervals */
726 if (dotarbuf(tarhandle,data,datalen) != datalen) {
727 DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
732 DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
739 /* pad tar file with zero's if we couldn't get entire file */
740 if (nread < finfo.size) {
741 DEBUG(0, ("Didn't get entire file. size=%.0f, nread=%d\n", (double)finfo.size, (int)nread));
742 if (padit(data, sizeof(data), finfo.size - nread))
743 DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
746 /* round tar file to nearest block */
747 if (finfo.size % TBLOCK)
748 dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
750 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
754 cli_close(cli, fnum);
758 struct timeval tp_end;
761 /* if shallitime is true then we didn't skip */
762 if (tar_reset && !dry_run)
763 (void) do_setrattr(finfo.name, FILE_ATTRIBUTE_ARCHIVE, ATTRRESET);
765 GetTimeOfDay(&tp_end);
767 (tp_end.tv_sec - tp_start.tv_sec)*1000 +
768 (tp_end.tv_usec - tp_start.tv_usec)/1000;
769 get_total_time_ms += this_time;
770 get_total_size += finfo.size;
774 DEBUG(0, ("%12.0f (%7.1f kb/s) %s\n",
775 (double)finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
779 /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
780 DEBUG(3,("(%g kb/s) (average %g kb/s)\n",
781 finfo.size / MAX(0.001, (1.024*this_time)),
782 get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
786 /****************************************************************************
787 Append single file to tar file (or not)
788 ***************************************************************************/
789 static void do_tar(file_info *finfo)
793 if (strequal(finfo->name,"..") || strequal(finfo->name,"."))
796 /* Is it on the exclude list ? */
797 if (!tar_excl && clipn) {
800 DEBUG(5, ("Excl: strlen(cur_dir) = %d\n", (int)strlen(cur_dir)));
802 safe_strcpy(exclaim, cur_dir, sizeof(pstring));
803 *(exclaim+strlen(exclaim)-1)='\0';
805 safe_strcat(exclaim, "\\", sizeof(pstring));
806 safe_strcat(exclaim, finfo->name, sizeof(exclaim));
808 DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
810 if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
812 (tar_re_search && !regexec(preg, exclaim, 0, NULL, 0))) {
814 (tar_re_search && mask_match(cli, exclaim, cliplist[0], True))) {
816 DEBUG(3,("Skipping file %s\n", exclaim));
821 if (finfo->mode & FILE_ATTRIBUTE_DIRECTORY)
823 pstring saved_curdir;
826 safe_strcpy(saved_curdir, cur_dir, sizeof(saved_curdir));
828 DEBUG(5, ("Sizeof(cur_dir)=%d, strlen(cur_dir)=%d, strlen(finfo->name)=%d\nname=%s,cur_dir=%s\n", (int)sizeof(cur_dir), (int)strlen(cur_dir), (int)strlen(finfo->name), finfo->name, cur_dir));
830 safe_strcat(cur_dir,finfo->name, sizeof(cur_dir));
831 safe_strcat(cur_dir,"\\", sizeof(cur_dir));
833 DEBUG(5, ("Writing a dir, Name = %s\n", cur_dir));
835 /* write a tar directory, don't bother with mode - just set it to
837 writetarheader(tarhandle, cur_dir, 0, finfo->mtime, "040755 \0", '5');
839 DEBUG(0,(" directory %s\n", cur_dir));
841 ntarf++; /* Make sure we have a file on there */
842 safe_strcpy(mtar_mask,cur_dir, sizeof(pstring));
843 safe_strcat(mtar_mask,"*", sizeof(pstring));
844 DEBUG(5, ("Doing list with mtar_mask: %s\n", mtar_mask));
845 do_list(mtar_mask, attribute, do_tar, False, True);
846 safe_strcpy(cur_dir,saved_curdir, sizeof(pstring));
850 safe_strcpy(rname,cur_dir, sizeof(pstring));
851 safe_strcat(rname,finfo->name, sizeof(pstring));
852 do_atar(rname,finfo->name,finfo);
856 /****************************************************************************
857 Convert from UNIX to DOS file names
858 ***************************************************************************/
859 static void unfixtarname(char *tptr, char *fp, int l, BOOL first)
861 /* remove '.' from start of file name, convert from unix /'s to
862 * dos \'s in path. Kill any absolute path names. But only if first!
865 DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
872 if (*fp == '\\' || *fp == '/') {
878 safe_strcpy(tptr, fp, l);
879 string_replace(tptr, '/', '\\');
883 /****************************************************************************
884 Move to the next block in the buffer, which may mean read in another set of
885 blocks. FIXME, we should allow more than one block to be skipped.
886 ****************************************************************************/
887 static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
889 int bufread, total = 0;
891 DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp));
895 if (*bufferp >= (ltarbuf + bufsiz)) {
897 DEBUG(5, ("Reading more data into ltarbuf ...\n"));
900 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>
901 * Fixes bug where read can return short if coming from
905 bufread = read(tarhandle, ltarbuf, bufsiz);
908 while (total < bufsiz) {
909 if (bufread < 0) { /* An error, return false */
910 return (total > 0 ? -2 : bufread);
918 bufread = read(tarhandle, <arbuf[total], bufsiz - total);
922 DEBUG(5, ("Total bytes read ... %i\n", total));
932 /* Skip a file, even if it includes a long file name? */
933 static int skip_file(int skipsize)
935 int dsize = skipsize;
937 DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
939 /* FIXME, we should skip more than one block at a time */
943 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
945 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
957 /*************************************************************
958 Get a file from the tar file and store it.
959 When this is called, tarbuf already contains the first
960 file block. This is a bit broken & needs fixing.
961 **************************************************************/
963 static int get_file(file_info2 finfo)
965 int fnum = -1, pos = 0, dsize = 0, rsize = 0, bpos = 0;
967 DEBUG(5, ("get_file: file: %s, size %i\n", finfo.name, (int)finfo.size));
969 if (ensurepath(finfo.name) &&
970 (fnum=cli_open(cli, finfo.name, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE)) == -1) {
971 DEBUG(0, ("abandoning restore\n"));
975 /* read the blocks from the tar file and write to the remote file */
977 rsize = finfo.size; /* This is how much to write */
981 /* We can only write up to the end of the buffer */
983 dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, 65520); /* Calculate the size to write */
984 dsize = MIN(dsize, rsize); /* Should be only what is left */
985 DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos));
987 if (cli_write(cli, fnum, 0, buffer_p + bpos, pos, dsize) != dsize) {
988 DEBUG(0, ("Error writing remote file\n"));
995 /* Now figure out how much to move in the buffer */
997 /* FIXME, we should skip more than one block at a time */
999 /* First, skip any initial part of the part written that is left over */
1000 /* from the end of the first TBLOCK */
1002 if ((bpos) && ((bpos + dsize) >= TBLOCK)) {
1004 dsize -= (TBLOCK - bpos); /* Get rid of the end of the first block */
1007 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) { /* and skip the block */
1008 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1016 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>.
1017 * If the file being extracted is an exact multiple of
1018 * TBLOCK bytes then we don't want to extract the next
1019 * block from the tarfile here, as it will be done in
1020 * the caller of get_file().
1023 while (((rsize != 0) && (dsize >= TBLOCK)) ||
1024 ((rsize == 0) && (dsize > TBLOCK))) {
1026 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1027 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1038 /* Now close the file ... */
1040 if (!cli_close(cli, fnum)) {
1041 DEBUG(0, ("Error closing remote file\n"));
1045 /* Now we update the creation date ... */
1047 DEBUG(5, ("Updating creation date on %s\n", finfo.name));
1049 if (!cli_setatr(cli, finfo.name, finfo.mode, finfo.mtime)) {
1050 if (tar_real_noisy) {
1051 DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
1052 /*return(False); */ /* Ignore, as Win95 does not allow changes */
1058 DEBUG(0, ("restore tar file %s of size %d bytes\n", finfo.name, (int)finfo.size));
1063 /* Create a directory. We just ensure that the path exists and return as there
1064 is no file associated with a directory
1066 static int get_dir(file_info2 finfo)
1069 DEBUG(0, ("restore directory %s\n", finfo.name));
1071 if (!ensurepath(finfo.name)) {
1073 DEBUG(0, ("Problems creating directory\n"));
1082 /* Get a file with a long file name ... first file has file name, next file
1083 has the data. We only want the long file name, as the loop in do_tarput
1084 will deal with the rest.
1086 static char * get_longfilename(file_info2 finfo)
1088 int namesize = finfo.size + strlen(cur_dir) + 2;
1089 char *longname = malloc(namesize);
1090 int offset = 0, left = finfo.size;
1093 DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
1094 DEBUG(5, ("Len = %d\n", (int)finfo.size));
1096 if (longname == NULL) {
1098 DEBUG(0, ("could not allocate buffer of size %d for longname\n",
1099 (int)(finfo.size + strlen(cur_dir) + 2)));
1103 /* First, add cur_dir to the long file name */
1105 if (strlen(cur_dir) > 0) {
1106 strncpy(longname, cur_dir, namesize);
1107 offset = strlen(cur_dir);
1110 /* Loop through the blocks picking up the name */
1114 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1116 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1121 unfixtarname(longname + offset, buffer_p, MIN(TBLOCK, finfo.size), first--);
1122 DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
1133 static void do_tarput(void)
1136 struct timeval tp_start;
1137 char *longfilename = NULL, linkflag;
1140 GetTimeOfDay(&tp_start);
1142 DEBUG(5, ("RJS do_tarput called ...\n"));
1144 buffer_p = tarbuf + tbufsiz; /* init this to force first read */
1146 /* Now read through those files ... */
1150 /* Get us to the next block, or the first block first time around */
1152 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1154 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1160 DEBUG(5, ("Reading the next header ...\n"));
1162 switch (readtarheader((union hblock *) buffer_p, &finfo, cur_dir)) {
1164 case -2: /* Hmm, not good, but not fatal */
1165 DEBUG(0, ("Skipping %s...\n", finfo.name));
1166 if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) &&
1167 !skip_file(finfo.size)) {
1169 DEBUG(0, ("Short file, bailing out...\n"));
1177 DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
1180 case 0: /* chksum is zero - looks like an EOF */
1181 DEBUG(0, ("tar: restored %d files and directories\n", ntarf));
1182 return; /* Hmmm, bad here ... */
1191 /* Now, do we have a long file name? */
1193 if (longfilename != NULL) {
1195 SAFE_FREE(finfo.name); /* Free the space already allocated */
1196 finfo.name = longfilename;
1197 longfilename = NULL;
1201 /* Well, now we have a header, process the file ... */
1203 /* Should we skip the file? We have the long name as well here */
1206 ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl)
1208 || (tar_re_search && !regexec(preg, finfo.name, 0, NULL, 0)));
1210 || (tar_re_search && mask_match(cli, finfo.name, cliplist[0], True)));
1213 DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
1217 skip_file(finfo.size);
1222 /* We only get this far if we should process the file */
1223 linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
1227 case '0': /* Should use symbolic names--FIXME */
1230 * Skip to the next block first, so we can get the file, FIXME, should
1231 * be in get_file ...
1232 * The 'finfo.size != 0' fix is from Bob Boehmer <boehmer@worldnet.att.net>
1233 * Fixes bug where file size in tarfile is zero.
1236 if ((finfo.size != 0) && next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1237 DEBUG(0, ("Short file, bailing out...\n"));
1240 if (!get_file(finfo)) {
1241 DEBUG(0, ("Abandoning restore\n"));
1248 if (!get_dir(finfo)) {
1249 DEBUG(0, ("Abandoning restore \n"));
1255 longfilename = get_longfilename(finfo);
1256 if (!longfilename) {
1257 DEBUG(0, ("abandoning restore\n"));
1261 DEBUG(5, ("Long file name: %s\n", longfilename));
1265 skip_file(finfo.size); /* Don't handle these yet */
1277 * samba interactive commands
1280 /****************************************************************************
1282 ***************************************************************************/
1288 if (!next_token_nr(NULL,buf,NULL,sizeof(buf)))
1290 DEBUG(0, ("blocksize <n>\n"));
1295 if (block < 0 || block > 65535)
1297 DEBUG(0, ("blocksize out of range"));
1302 DEBUG(2,("blocksize is now %d\n", blocksize));
1307 /****************************************************************************
1308 command to set incremental / reset mode
1309 ***************************************************************************/
1310 int cmd_tarmode(void)
1314 while (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1315 if (strequal(buf, "full"))
1317 else if (strequal(buf, "inc"))
1319 else if (strequal(buf, "reset"))
1321 else if (strequal(buf, "noreset"))
1323 else if (strequal(buf, "system"))
1325 else if (strequal(buf, "nosystem"))
1327 else if (strequal(buf, "hidden"))
1329 else if (strequal(buf, "nohidden"))
1331 else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
1333 else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
1335 else DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
1338 DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
1339 tar_inc ? "incremental" : "full",
1340 tar_system ? "system" : "nosystem",
1341 tar_hidden ? "hidden" : "nohidden",
1342 tar_reset ? "reset" : "noreset",
1343 tar_noisy ? "verbose" : "quiet"));
1348 /****************************************************************************
1349 Feeble attrib command
1350 ***************************************************************************/
1351 int cmd_setmode(void)
1359 attra[0] = attra[1] = 0;
1361 if (!next_token_nr(NULL,buf,NULL,sizeof(buf)))
1363 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1367 safe_strcpy(fname, cur_dir, sizeof(pstring));
1368 safe_strcat(fname, buf, sizeof(pstring));
1370 while (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1379 case 'r': attra[direct]|=FILE_ATTRIBUTE_READONLY;
1381 case 'h': attra[direct]|=FILE_ATTRIBUTE_HIDDEN;
1383 case 's': attra[direct]|=FILE_ATTRIBUTE_SYSTEM;
1385 case 'a': attra[direct]|=FILE_ATTRIBUTE_ARCHIVE;
1387 default: DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1392 if (attra[ATTRSET]==0 && attra[ATTRRESET]==0)
1394 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1398 DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1399 do_setrattr(fname, attra[ATTRSET], ATTRSET);
1400 do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
1405 /****************************************************************************
1406 Principal command for creating / extracting
1407 ***************************************************************************/
1414 if (!next_token_nr(NULL,buf,NULL,sizeof(buf)))
1416 DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
1420 argl=toktocliplist(&argcl, NULL);
1421 if (!tar_parseargs(argcl, argl, buf, 0))
1431 /****************************************************************************
1432 Command line (option) version
1433 ***************************************************************************/
1434 int process_tar(void)
1450 if (clipn && tar_excl) {
1454 for (i=0; i<clipn; i++) {
1455 DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
1457 if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1458 *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1461 if (strrchr_m(cliplist[i], '\\')) {
1464 safe_strcpy(saved_dir, cur_dir, sizeof(pstring));
1466 if (*cliplist[i]=='\\') {
1467 safe_strcpy(tarmac, cliplist[i], sizeof(pstring));
1469 safe_strcpy(tarmac, cur_dir, sizeof(pstring));
1470 safe_strcat(tarmac, cliplist[i], sizeof(pstring));
1472 safe_strcpy(cur_dir, tarmac, sizeof(pstring));
1473 *(strrchr_m(cur_dir, '\\')+1)='\0';
1475 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1476 do_list(tarmac,attribute,do_tar, False, True);
1477 safe_strcpy(cur_dir,saved_dir, sizeof(pstring));
1479 safe_strcpy(tarmac, cur_dir, sizeof(pstring));
1480 safe_strcat(tarmac, cliplist[i], sizeof(pstring));
1481 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1482 do_list(tarmac,attribute,do_tar, False, True);
1487 safe_strcpy(mask,cur_dir, sizeof(pstring));
1488 DEBUG(5, ("process_tar, do_list with mask: %s\n", mask));
1489 safe_strcat(mask,"\\*", sizeof(pstring));
1490 do_list(mask,attribute,do_tar,False, True);
1493 if (ntarf) dotareof(tarhandle);
1497 DEBUG(0, ("tar: dumped %d files and directories\n", ntarf));
1498 DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf));
1502 if (must_free_cliplist) {
1504 for (i = 0; i < clipn; ++i) {
1505 SAFE_FREE(cliplist[i]);
1507 SAFE_FREE(cliplist);
1510 must_free_cliplist = False;
1516 /****************************************************************************
1517 Find a token (filename) in a clip list
1518 ***************************************************************************/
1519 static int clipfind(char **aret, int ret, char *tok)
1521 if (aret==NULL) return 0;
1523 /* ignore leading slashes or dots in token */
1524 while(strchr_m("/\\.", *tok)) tok++;
1529 /* ignore leading slashes or dots in list */
1530 while(strchr_m("/\\.", *pkey)) pkey++;
1532 if (!strslashcmp(pkey, tok)) return 1;
1538 /****************************************************************************
1539 Read list of files to include from the file and initialize cliplist
1541 ***************************************************************************/
1542 static int read_inclusion_file(char *filename)
1544 XFILE *inclusion = NULL;
1545 char buf[MAXPATHLEN + 1];
1546 char *inclusion_buffer = NULL;
1547 int inclusion_buffer_size = 0;
1548 int inclusion_buffer_sofar = 0;
1555 buf[MAXPATHLEN] = '\0'; /* guarantee null-termination */
1556 if ((inclusion = x_fopen(filename, O_RDONLY, 0)) == NULL) {
1557 /* XXX It would be better to include a reason for failure, but without
1558 * autoconf, it's hard to use strerror, sys_errlist, etc.
1560 DEBUG(0,("Unable to open inclusion file %s\n", filename));
1564 while ((! error) && (x_fgets(buf, sizeof(buf)-1, inclusion))) {
1565 if (inclusion_buffer == NULL) {
1566 inclusion_buffer_size = 1024;
1567 if ((inclusion_buffer = malloc(inclusion_buffer_size)) == NULL) {
1568 DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1574 if (buf[strlen(buf)-1] == '\n') {
1575 buf[strlen(buf)-1] = '\0';
1578 if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1580 inclusion_buffer_size *= 2;
1581 ib = Realloc(inclusion_buffer,inclusion_buffer_size);
1583 DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1584 inclusion_buffer_size));
1588 else inclusion_buffer = ib;
1591 safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
1592 inclusion_buffer_sofar += strlen(buf) + 1;
1595 x_fclose(inclusion);
1598 /* Allocate an array of clipn + 1 char*'s for cliplist */
1599 cliplist = malloc((clipn + 1) * sizeof(char *));
1600 if (cliplist == NULL) {
1601 DEBUG(0,("failure allocating memory for cliplist\n"));
1604 cliplist[clipn] = NULL;
1605 p = inclusion_buffer;
1606 for (i = 0; (! error) && (i < clipn); i++) {
1607 /* set current item to NULL so array will be null-terminated even if
1608 * malloc fails below. */
1610 if ((tmpstr = (char *)malloc(strlen(p)+1)) == NULL) {
1611 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
1614 unfixtarname(tmpstr, p, strlen(p) + 1, True);
1615 cliplist[i] = tmpstr;
1616 if ((p = strchr_m(p, '\000')) == NULL) {
1617 DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1623 must_free_cliplist = True;
1627 SAFE_FREE(inclusion_buffer);
1631 /* We know cliplist is always null-terminated */
1632 for (pp = cliplist; *pp; ++pp) {
1635 SAFE_FREE(cliplist);
1637 must_free_cliplist = False;
1642 /* cliplist and its elements are freed at the end of process_tar. */
1646 /****************************************************************************
1647 Parse tar arguments. Sets tar_type, tar_excl, etc.
1648 ***************************************************************************/
1649 int tar_parseargs(int argc, char *argv[], const char *Optarg, int Optind)
1651 char tar_clipfl='\0';
1653 /* Reset back to defaults - could be from interactive version
1654 * reset mode and archive mode left as they are though
1666 if (tar_type=='c') {
1667 printf("Tar must be followed by only one of c or x.\n");
1673 if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1674 DEBUG(0,("Option b must be followed by valid blocksize\n"));
1685 DEBUG(0,("Option N must be followed by valid file name\n"));
1688 SMB_STRUCT_STAT stbuf;
1689 extern time_t newer_than;
1691 if (sys_stat(argv[Optind], &stbuf) == 0) {
1692 newer_than = stbuf.st_mtime;
1693 DEBUG(1,("Getting files newer than %s",
1694 asctime(LocalTime(&newer_than))));
1697 DEBUG(0,("Error setting newer-than time\n"));
1710 DEBUG(0,("Only one of I,X,F must be specified\n"));
1717 DEBUG(0,("Only one of I,X,F must be specified\n"));
1724 DEBUG(0,("Only one of I,X,F must be specified\n"));
1730 DEBUG(0, ("tar_re_search set\n"));
1731 tar_re_search = True;
1734 if (tar_type == 'c') {
1735 DEBUG(0, ("dry_run set\n"));
1738 DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1743 DEBUG(0,("Unknown tar option\n"));
1748 printf("Option T must be followed by one of c or x.\n");
1752 /* tar_excl is true if cliplist lists files to be included.
1753 * Both 'I' and 'F' mean include. */
1754 tar_excl=tar_clipfl!='X';
1756 if (tar_clipfl=='F') {
1757 if (argc-Optind-1 != 1) {
1758 DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1761 if (! read_inclusion_file(argv[Optind+1])) {
1764 } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
1769 cliplist=argv+Optind+1;
1770 clipn=argc-Optind-1;
1773 if ((tmplist=malloc(clipn*sizeof(char *))) == NULL) {
1774 DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n",
1780 for (clipcount = 0; clipcount < clipn; clipcount++) {
1782 DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1784 if ((tmpstr = (char *)malloc(strlen(cliplist[clipcount])+1)) == NULL) {
1785 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n",
1790 unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
1791 tmplist[clipcount] = tmpstr;
1792 DEBUG(5, ("Processed an item, %s\n", tmpstr));
1794 DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1797 must_free_cliplist = True;
1800 if (Optind+1<argc && tar_re_search) { /* Doing regular expression seaches */
1804 if ((preg = (regex_t *)malloc(65536)) == NULL) {
1806 DEBUG(0, ("Could not allocate buffer for regular expression search\n"));
1811 if (errcode = regcomp(preg, argv[Optind + 1], REG_EXTENDED)) {
1815 errlen = regerror(errcode, preg, errstr, sizeof(errstr) - 1);
1817 DEBUG(0, ("Could not compile pattern buffer for re search: %s\n%s\n", argv[Optind + 1], errstr));
1823 clipn=argc-Optind-1;
1824 cliplist=argv+Optind+1;
1828 if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1829 /* Sets tar handle to either 0 or 1, as appropriate */
1830 tarhandle=(tar_type=='c');
1832 * Make sure that dbf points to stderr if we are using stdout for
1836 setup_logging("clitar", DEBUG_STDERR);
1838 if (tar_type=='c' && (dry_run || strcmp(argv[Optind], "/dev/null")==0))
1841 DEBUG(0,("Output is /dev/null, assuming dry_run\n"));
1846 if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1)
1847 || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0))
1849 DEBUG(0,("Error opening local file %s - %s\n",
1850 argv[Optind], strerror(errno)));