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);
44 typedef struct file_info_struct file_info2;
46 struct file_info_struct {
51 /* These times are normally kept in GMT */
55 char *name; /* This is dynamically allocate */
57 file_info2 *next, *prev; /* Used in the stack ... */
65 #define SEPARATORS " \t\n\r"
66 extern struct cli_state *cli;
68 /* These defines are for the do_setrattr routine, to indicate
69 * setting and reseting of file attributes in the function call */
73 static uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
75 #ifndef CLIENT_TIMEOUT
76 #define CLIENT_TIMEOUT (30*1000)
79 static char *tarbuf, *buffer_p;
80 static int tp, ntarf, tbufsiz;
82 /* Incremental mode */
83 static BOOL tar_inc=False;
84 /* Reset archive bit */
85 static BOOL tar_reset=False;
86 /* Include / exclude mode (true=include, false=exclude) */
87 static BOOL tar_excl=True;
88 /* use regular expressions for search on file names */
89 static BOOL tar_re_search=False;
93 /* Do not dump anything, just calculate sizes */
94 static BOOL dry_run=False;
95 /* Dump files with System attribute */
96 static BOOL tar_system=True;
97 /* Dump files with Hidden attribute */
98 static BOOL tar_hidden=True;
99 /* Be noisy - make a catalogue */
100 static BOOL tar_noisy=True;
101 static BOOL tar_real_noisy=False; /* Don't want to be really noisy by default */
104 static char **cliplist=NULL;
106 static BOOL must_free_cliplist = False;
108 extern file_info def_finfo;
109 extern BOOL lowercase;
111 extern BOOL readbraw_supported;
113 extern pstring cur_dir;
114 extern int get_total_time_ms;
115 extern int get_total_size;
117 static int blocksize=20;
118 static int tarhandle;
120 static void writetarheader(int f, const char *aname, SMB_BIG_UINT size, time_t mtime,
121 const char *amode, unsigned char ftype);
122 static void do_atar(char *rname,char *lname,file_info *finfo1);
123 static void do_tar(file_info *finfo);
124 static void oct_it(SMB_BIG_UINT value, int ndgs, char *p);
125 static void fixtarname(char *tptr, const char *fp, size_t l);
126 static int dotarbuf(int f, char *b, int n);
127 static void dozerobuf(int f, int n);
128 static void dotareof(int f);
129 static void initarbuf(void);
131 /* restore functions */
132 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix);
133 static long unoct(char *p, int ndgs);
134 static void do_tarput(void);
135 static void unfixtarname(char *tptr, char *fp, int l, BOOL first);
138 * tar specific utitlities
141 /*******************************************************************
142 Create a string of size size+1 (for the null)
143 *******************************************************************/
145 static char *string_create_s(int size)
149 tmp = (char *)malloc(size+1);
152 DEBUG(0, ("Out of memory in string_create_s\n"));
158 /****************************************************************************
159 Write a tar header to buffer
160 ****************************************************************************/
162 static void writetarheader(int f, const char *aname, SMB_BIG_UINT size, time_t mtime,
163 const char *amode, unsigned char ftype)
169 DEBUG(5, ("WriteTarHdr, Type = %c, Size= %.0f, Name = %s\n", ftype, (double)size, aname));
171 memset(hb.dummy, 0, sizeof(hb.dummy));
174 /* We will be prepending a '.' in fixtarheader so use +2 to
175 * take care of the . and terminating zero. JRA.
178 /* write a GNU tar style long header */
180 b = (char *)malloc(l+TBLOCK+100);
182 DEBUG(0,("out of memory\n"));
185 writetarheader(f, "/./@LongLink", l+2, 0, " 0 \0", 'L');
186 memset(b, 0, l+TBLOCK+100);
187 fixtarname(b, aname, l+2);
189 DEBUG(5, ("File name in tar file: %s, size=%d, \n", b, (int)strlen(b)));
190 dotarbuf(f, b, TBLOCK*(((i-1)/TBLOCK)+1));
194 fixtarname(hb.dbuf.name, aname, (l+2 >= NAMSIZ) ? NAMSIZ : l + 2);
197 strlower_m(hb.dbuf.name);
199 /* write out a "standard" tar format header */
201 hb.dbuf.name[NAMSIZ-1]='\0';
202 safe_strcpy(hb.dbuf.mode, amode, sizeof(hb.dbuf.mode)-1);
203 oct_it((SMB_BIG_UINT)0, 8, hb.dbuf.uid);
204 oct_it((SMB_BIG_UINT)0, 8, hb.dbuf.gid);
205 oct_it((SMB_BIG_UINT) size, 13, hb.dbuf.size);
206 if (size > (SMB_BIG_UINT)077777777777LL) {
208 /* This is a non-POSIX compatible extention to store files
211 memset(hb.dbuf.size, 0, 4);
213 for (i = 8, jp=(char*)&size; i; i--)
214 hb.dbuf.size[i+3] = *(jp++);
216 oct_it((SMB_BIG_UINT) mtime, 13, hb.dbuf.mtime);
217 memcpy(hb.dbuf.chksum, " ", sizeof(hb.dbuf.chksum));
218 memset(hb.dbuf.linkname, 0, NAMSIZ);
219 hb.dbuf.linkflag=ftype;
221 for (chk=0, i=sizeof(hb.dummy), jp=hb.dummy; --i>=0;)
224 oct_it((SMB_BIG_UINT) chk, 8, hb.dbuf.chksum);
225 hb.dbuf.chksum[6] = '\0';
227 (void) dotarbuf(f, hb.dummy, sizeof(hb.dummy));
230 /****************************************************************************
231 Read a tar header into a hblock structure, and validate
232 ***************************************************************************/
234 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix)
241 * read in a "standard" tar format header - we're not that interested
242 * in that many fields, though
245 /* check the checksum */
246 for (chk=0, i=sizeof(hb->dummy), jp=hb->dummy; --i>=0;)
252 /* compensate for blanks in chksum header */
253 for (i=sizeof(hb->dbuf.chksum), jp=hb->dbuf.chksum; --i>=0;)
256 chk += ' ' * sizeof(hb->dbuf.chksum);
258 fchk=unoct(hb->dbuf.chksum, sizeof(hb->dbuf.chksum));
260 DEBUG(5, ("checksum totals chk=%ld fchk=%ld chksum=%s\n",
261 chk, fchk, hb->dbuf.chksum));
264 DEBUG(0, ("checksums don't match %ld %ld\n", fchk, chk));
265 dump_data(5, (char *)hb - TBLOCK, TBLOCK *3);
269 if ((finfo->name = string_create_s(strlen(prefix) + strlen(hb -> dbuf.name) + 3)) == NULL) {
270 DEBUG(0, ("Out of space creating file_info2 for %s\n", hb -> dbuf.name));
274 safe_strcpy(finfo->name, prefix, strlen(prefix) + strlen(hb -> dbuf.name) + 3);
276 /* use l + 1 to do the null too; do prefix - prefcnt to zap leading slash */
277 unfixtarname(finfo->name + strlen(prefix), hb->dbuf.name,
278 strlen(hb->dbuf.name) + 1, True);
280 /* can't handle some links at present */
281 if ((hb->dbuf.linkflag != '0') && (hb -> dbuf.linkflag != '5')) {
282 if (hb->dbuf.linkflag == 0) {
283 DEBUG(6, ("Warning: NULL link flag (gnu tar archive ?) %s\n",
286 if (hb -> dbuf.linkflag == 'L') { /* We have a longlink */
287 /* Do nothing here at the moment. do_tarput will handle this
288 as long as the longlink gets back to it, as it has to advance
289 the buffer pointer, etc */
291 DEBUG(0, ("this tar file appears to contain some kind \
292 of link other than a GNUtar Longlink - ignoring\n"));
298 if ((unoct(hb->dbuf.mode, sizeof(hb->dbuf.mode)) & S_IFDIR) ||
299 (*(finfo->name+strlen(finfo->name)-1) == '\\')) {
302 finfo->mode=0; /* we don't care about mode at the moment, we'll
303 * just make it a regular file */
307 * Bug fix by richard@sj.co.uk
309 * REC: restore times correctly (as does tar)
310 * We only get the modification time of the file; set the creation time
311 * from the mod. time, and the access time to current time
313 finfo->mtime = finfo->ctime = strtol(hb->dbuf.mtime, NULL, 8);
314 finfo->atime = time(NULL);
315 finfo->size = unoct(hb->dbuf.size, sizeof(hb->dbuf.size));
320 /****************************************************************************
321 Write out the tar buffer to tape or wherever
322 ****************************************************************************/
324 static int dotarbuf(int f, char *b, int n)
331 /* This routine and the next one should be the only ones that do write()s */
332 if (tp + n >= tbufsiz) {
336 memcpy(tarbuf + tp, b, diff);
337 fail=fail && (1+write(f, tarbuf, tbufsiz));
342 while (n >= tbufsiz) {
343 fail=fail && (1 + write(f, b, tbufsiz));
350 memcpy(tarbuf+tp, b, n);
354 return(fail ? writ : 0);
357 /****************************************************************************
358 Write zeros to buffer / tape
359 ****************************************************************************/
361 static void dozerobuf(int f, int n)
363 /* short routine just to write out n zeros to buffer -
364 * used to round files to nearest block
365 * and to do tar EOFs */
370 if (n+tp >= tbufsiz) {
371 memset(tarbuf+tp, 0, tbufsiz-tp);
372 write(f, tarbuf, tbufsiz);
373 memset(tarbuf, 0, (tp+=n-tbufsiz));
375 memset(tarbuf+tp, 0, n);
380 /****************************************************************************
382 ****************************************************************************/
384 static void initarbuf(void)
386 /* initialize tar buffer */
387 tbufsiz=blocksize*TBLOCK;
388 tarbuf=malloc(tbufsiz); /* FIXME: We might not get the buffer */
390 /* reset tar buffer pointer and tar file counter and total dumped */
391 tp=0; ntarf=0; ttarf=0;
394 /****************************************************************************
395 Write two zero blocks at end of file
396 ****************************************************************************/
398 static void dotareof(int f)
400 SMB_STRUCT_STAT stbuf;
401 /* Two zero blocks at end of file, write out full buffer */
406 (void) dozerobuf(f, TBLOCK);
407 (void) dozerobuf(f, TBLOCK);
409 if (sys_fstat(f, &stbuf) == -1) {
410 DEBUG(0, ("Couldn't stat file handle\n"));
414 /* Could be a pipe, in which case S_ISREG should fail,
415 * and we should write out at full size */
417 write(f, tarbuf, S_ISREG(stbuf.st_mode) ? tp : tbufsiz);
420 /****************************************************************************
421 (Un)mangle DOS pathname, make nonabsolute
422 ****************************************************************************/
424 static void fixtarname(char *tptr, const char *fp, size_t l)
426 /* add a '.' to start of file name, convert from ugly dos \'s in path
427 * to lovely unix /'s :-} */
431 StrnCpy(tptr, fp, l-1);
432 string_replace(tptr, '\\', '/');
435 /****************************************************************************
436 Convert from decimal to octal string
437 ****************************************************************************/
439 static void oct_it (SMB_BIG_UINT value, int ndgs, char *p)
441 /* Converts long to octal string, pads with leading zeros */
443 /* skip final null, but do final space */
447 /* Loop does at least one digit */
449 p[--ndgs] = '0' + (char) (value & 7);
451 } while (ndgs > 0 && value != 0);
453 /* Do leading zeros */
458 /****************************************************************************
459 Convert from octal string to long
460 ***************************************************************************/
462 static long unoct(char *p, int ndgs)
465 /* Converts octal string to long, ignoring any non-digit */
468 if (isdigit((int)*p))
469 value = (value << 3) | (long) (*p - '0');
477 /****************************************************************************
478 Compare two strings in a slash insensitive way, allowing s1 to match s2
479 if s1 is an "initial" string (up to directory marker). Thus, if s2 is
480 a file in any subdirectory of s1, declare a match.
481 ***************************************************************************/
483 static int strslashcmp(char *s1, char *s2)
487 while(*s1 && *s2 && (*s1 == *s2 || tolower(*s1) == tolower(*s2) ||
488 (*s1 == '\\' && *s2=='/') || (*s1 == '/' && *s2=='\\'))) {
492 /* if s1 has a trailing slash, it compared equal, so s1 is an "initial"
495 if (!*s1 && s1 != s1_0 && (*(s1-1) == '/' || *(s1-1) == '\\'))
498 /* ignore trailing slash on s1 */
499 if (!*s2 && (*s1 == '/' || *s1 == '\\') && !*(s1+1))
502 /* check for s1 is an "initial" string of s2 */
503 if ((*s2 == '/' || *s2 == '\\') && !*s1)
509 /****************************************************************************
510 Ensure a remote path exists (make if necessary)
511 ***************************************************************************/
513 static BOOL ensurepath(char *fname)
515 /* *must* be called with buffer ready malloc'ed */
516 /* ensures path exists */
518 char *partpath, *ffname;
519 char *p=fname, *basehack;
521 DEBUG(5, ( "Ensurepath called with: %s\n", fname));
523 partpath = string_create_s(strlen(fname));
524 ffname = string_create_s(strlen(fname));
526 if ((partpath == NULL) || (ffname == NULL)){
527 DEBUG(0, ("Out of memory in ensurepath: %s\n", fname));
533 /* fname copied to ffname so can strtok */
535 safe_strcpy(ffname, fname, strlen(fname));
537 /* do a `basename' on ffname, so don't try and make file name directory */
538 if ((basehack=strrchr_m(ffname, '\\')) == NULL)
543 p=strtok(ffname, "\\");
546 safe_strcat(partpath, p, strlen(fname) + 1);
548 if (!cli_chkpath(cli, partpath)) {
549 if (!cli_mkdir(cli, partpath)) {
550 DEBUG(0, ("Error mkdirhiering\n"));
553 DEBUG(3, ("mkdirhiering %s\n", partpath));
557 safe_strcat(partpath, "\\", strlen(fname) + 1);
558 p = strtok(NULL,"/\\");
564 static int padit(char *buf, int bufsize, int padsize)
569 DEBUG(5, ("Padding with %d zeros\n", padsize));
570 memset(buf, 0, bufsize);
571 while( !berr && padsize > 0 ) {
572 bytestowrite= MIN(bufsize, padsize);
573 berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite;
574 padsize -= bytestowrite;
580 static void do_setrattr(char *name, uint16 attr, int set)
584 if (!cli_getatr(cli, name, &oldattr, NULL, NULL)) return;
586 if (set == ATTRSET) {
589 attr = oldattr & ~attr;
592 if (!cli_setatr(cli, name, attr, 0)) {
593 DEBUG(1,("setatr failed: %s\n", cli_errstr(cli)));
597 /****************************************************************************
598 append one remote file to the tar file
599 ***************************************************************************/
601 static void do_atar(char *rname,char *lname,file_info *finfo1)
604 SMB_BIG_UINT nread=0;
607 BOOL close_done = False;
608 BOOL shallitime=True;
610 int read_size = 65520;
613 struct timeval tp_start;
615 GetTimeOfDay(&tp_start);
617 ftype = '0'; /* An ordinary file ... */
620 finfo.size = finfo1 -> size;
621 finfo.mode = finfo1 -> mode;
622 finfo.uid = finfo1 -> uid;
623 finfo.gid = finfo1 -> gid;
624 finfo.mtime = finfo1 -> mtime;
625 finfo.atime = finfo1 -> atime;
626 finfo.ctime = finfo1 -> ctime;
627 finfo.name = finfo1 -> name;
629 finfo.size = def_finfo.size;
630 finfo.mode = def_finfo.mode;
631 finfo.uid = def_finfo.uid;
632 finfo.gid = def_finfo.gid;
633 finfo.mtime = def_finfo.mtime;
634 finfo.atime = def_finfo.atime;
635 finfo.ctime = def_finfo.ctime;
636 finfo.name = def_finfo.name;
640 DEBUG(3,("skipping file %s of size %12.0f bytes\n", finfo.name,
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));
666 if (!cli_getattrE(cli, fnum, &finfo.mode, &finfo.size, NULL, &finfo.atime, &finfo.mtime)) {
667 DEBUG(0, ("getattrE: %s\n", cli_errstr(cli)));
670 finfo.ctime = finfo.mtime;
673 DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
675 if (tar_inc && !(finfo.mode & aARCH)) {
676 DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
678 } else if (!tar_system && (finfo.mode & aSYSTEM)) {
679 DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
681 } else if (!tar_hidden && (finfo.mode & aHIDDEN)) {
682 DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
685 DEBUG(3,("getting file %s of size %.0f bytes as a tar file %s",
686 finfo.name, (double)finfo.size, lname));
688 /* write a tar header, don't bother with mode - just set to 100644 */
689 writetarheader(tarhandle, rname, finfo.size, finfo.mtime, "100644 \0", ftype);
691 while (nread < finfo.size && !close_done) {
693 DEBUG(3,("nread=%.0f\n",(double)nread));
695 datalen = cli_read(cli, fnum, data, nread, read_size);
698 DEBUG(0,("Error reading file %s : %s\n", rname, cli_errstr(cli)));
704 /* if file size has increased since we made file size query, truncate
705 read so tar header for this file will be correct.
708 if (nread > finfo.size) {
709 datalen -= nread - finfo.size;
710 DEBUG(0,("File size change - truncating %s to %.0f bytes\n",
711 finfo.name, (double)finfo.size));
714 /* add received bits of file to buffer - dotarbuf will
715 * write out in 512 byte intervals */
717 if (dotarbuf(tarhandle,data,datalen) != datalen) {
718 DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
723 DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
730 /* pad tar file with zero's if we couldn't get entire file */
731 if (nread < finfo.size) {
732 DEBUG(0, ("Didn't get entire file. size=%.0f, nread=%d\n",
733 (double)finfo.size, (int)nread));
734 if (padit(data, sizeof(data), finfo.size - nread))
735 DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
738 /* round tar file to nearest block */
739 if (finfo.size % TBLOCK)
740 dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
742 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
746 cli_close(cli, fnum);
749 struct timeval tp_end;
752 /* if shallitime is true then we didn't skip */
753 if (tar_reset && !dry_run)
754 (void) do_setrattr(finfo.name, aARCH, ATTRRESET);
756 GetTimeOfDay(&tp_end);
757 this_time = (tp_end.tv_sec - tp_start.tv_sec)*1000 + (tp_end.tv_usec - tp_start.tv_usec)/1000;
758 get_total_time_ms += this_time;
759 get_total_size += finfo.size;
762 DEBUG(0, ("%12.0f (%7.1f kb/s) %s\n",
763 (double)finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
767 /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
768 DEBUG(3,("(%g kb/s) (average %g kb/s)\n",
769 finfo.size / MAX(0.001, (1.024*this_time)),
770 get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
774 /****************************************************************************
775 Append single file to tar file (or not)
776 ***************************************************************************/
778 static void do_tar(file_info *finfo)
782 if (strequal(finfo->name,"..") || strequal(finfo->name,"."))
785 /* Is it on the exclude list ? */
786 if (!tar_excl && clipn) {
789 DEBUG(5, ("Excl: strlen(cur_dir) = %d\n", (int)strlen(cur_dir)));
791 pstrcpy(exclaim, cur_dir);
792 *(exclaim+strlen(exclaim)-1)='\0';
794 pstrcat(exclaim, "\\");
795 pstrcat(exclaim, finfo->name);
797 DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
799 if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
801 (tar_re_search && !regexec(preg, exclaim, 0, NULL, 0))) {
803 (tar_re_search && mask_match(exclaim, cliplist[0], True))) {
805 DEBUG(3,("Skipping file %s\n", exclaim));
810 if (finfo->mode & aDIR) {
811 pstring saved_curdir;
814 pstrcpy(saved_curdir, cur_dir);
816 DEBUG(5, ("Sizeof(cur_dir)=%d, strlen(cur_dir)=%d, \
817 strlen(finfo->name)=%d\nname=%s,cur_dir=%s\n",
818 (int)sizeof(cur_dir), (int)strlen(cur_dir),
819 (int)strlen(finfo->name), finfo->name, cur_dir));
821 pstrcat(cur_dir,finfo->name);
822 pstrcat(cur_dir,"\\");
824 DEBUG(5, ("Writing a dir, Name = %s\n", cur_dir));
826 /* write a tar directory, don't bother with mode - just set it to
828 writetarheader(tarhandle, cur_dir, 0, finfo->mtime, "040755 \0", '5');
830 DEBUG(0,(" directory %s\n", cur_dir));
832 ntarf++; /* Make sure we have a file on there */
833 pstrcpy(mtar_mask,cur_dir);
834 pstrcat(mtar_mask,"*");
835 DEBUG(5, ("Doing list with mtar_mask: %s\n", mtar_mask));
836 do_list(mtar_mask, attribute, do_tar, False, True);
837 pstrcpy(cur_dir,saved_curdir);
839 pstrcpy(rname,cur_dir);
840 pstrcat(rname,finfo->name);
841 do_atar(rname,finfo->name,finfo);
845 /****************************************************************************
846 Convert from UNIX to DOS file names
847 ***************************************************************************/
849 static void unfixtarname(char *tptr, char *fp, int l, BOOL first)
851 /* remove '.' from start of file name, convert from unix /'s to
852 * dos \'s in path. Kill any absolute path names. But only if first!
855 DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
862 if (*fp == '\\' || *fp == '/') {
868 safe_strcpy(tptr, fp, l);
869 string_replace(tptr, '/', '\\');
872 /****************************************************************************
873 Move to the next block in the buffer, which may mean read in another set of
874 blocks. FIXME, we should allow more than one block to be skipped.
875 ****************************************************************************/
877 static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
879 int bufread, total = 0;
881 DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp));
885 if (*bufferp >= (ltarbuf + bufsiz)) {
887 DEBUG(5, ("Reading more data into ltarbuf ...\n"));
890 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>
891 * Fixes bug where read can return short if coming from
895 bufread = read(tarhandle, ltarbuf, bufsiz);
898 while (total < bufsiz) {
899 if (bufread < 0) { /* An error, return false */
900 return (total > 0 ? -2 : bufread);
908 bufread = read(tarhandle, <arbuf[total], bufsiz - total);
912 DEBUG(5, ("Total bytes read ... %i\n", total));
920 /* Skip a file, even if it includes a long file name? */
921 static int skip_file(int skipsize)
923 int dsize = skipsize;
925 DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
927 /* FIXME, we should skip more than one block at a time */
930 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
931 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
940 /*************************************************************
941 Get a file from the tar file and store it.
942 When this is called, tarbuf already contains the first
943 file block. This is a bit broken & needs fixing.
944 **************************************************************/
946 static int get_file(file_info2 finfo)
948 int fnum = -1, pos = 0, dsize = 0, bpos = 0;
949 SMB_BIG_UINT rsize = 0;
951 DEBUG(5, ("get_file: file: %s, size %.0f\n", finfo.name, (double)finfo.size));
953 if (ensurepath(finfo.name) &&
954 (fnum=cli_open(cli, finfo.name, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE)) == -1) {
955 DEBUG(0, ("abandoning restore\n"));
959 /* read the blocks from the tar file and write to the remote file */
961 rsize = finfo.size; /* This is how much to write */
965 /* We can only write up to the end of the buffer */
966 dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, 65520); /* Calculate the size to write */
967 dsize = MIN(dsize, rsize); /* Should be only what is left */
968 DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos));
970 if (cli_write(cli, fnum, 0, buffer_p + bpos, pos, dsize) != dsize) {
971 DEBUG(0, ("Error writing remote file\n"));
978 /* Now figure out how much to move in the buffer */
980 /* FIXME, we should skip more than one block at a time */
982 /* First, skip any initial part of the part written that is left over */
983 /* from the end of the first TBLOCK */
985 if ((bpos) && ((bpos + dsize) >= TBLOCK)) {
986 dsize -= (TBLOCK - bpos); /* Get rid of the end of the first block */
989 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) { /* and skip the block */
990 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
996 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>.
997 * If the file being extracted is an exact multiple of
998 * TBLOCK bytes then we don't want to extract the next
999 * block from the tarfile here, as it will be done in
1000 * the caller of get_file().
1003 while (((rsize != 0) && (dsize >= TBLOCK)) ||
1004 ((rsize == 0) && (dsize > TBLOCK))) {
1006 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1007 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1016 /* Now close the file ... */
1018 if (!cli_close(cli, fnum)) {
1019 DEBUG(0, ("Error closing remote file\n"));
1023 /* Now we update the creation date ... */
1024 DEBUG(5, ("Updating creation date on %s\n", finfo.name));
1026 if (!cli_setatr(cli, finfo.name, finfo.mode, finfo.mtime)) {
1027 if (tar_real_noisy) {
1028 DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
1029 /*return(False); */ /* Ignore, as Win95 does not allow changes */
1034 DEBUG(0, ("restore tar file %s of size %.0f bytes\n", finfo.name, (double)finfo.size));
1038 /* Create a directory. We just ensure that the path exists and return as there
1039 is no file associated with a directory
1041 static int get_dir(file_info2 finfo)
1043 DEBUG(0, ("restore directory %s\n", finfo.name));
1045 if (!ensurepath(finfo.name)) {
1046 DEBUG(0, ("Problems creating directory\n"));
1053 /* Get a file with a long file name ... first file has file name, next file
1054 has the data. We only want the long file name, as the loop in do_tarput
1055 will deal with the rest.
1057 static char * get_longfilename(file_info2 finfo)
1059 int namesize = strlen(finfo.name) + strlen(cur_dir) + 2;
1060 char *longname = malloc(namesize);
1061 int offset = 0, left = finfo.size;
1064 DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
1065 DEBUG(5, ("Len = %.0f\n", (double)finfo.size));
1067 if (longname == NULL) {
1068 DEBUG(0, ("could not allocate buffer of size %d for longname\n", namesize));
1072 /* First, add cur_dir to the long file name */
1074 if (strlen(cur_dir) > 0) {
1075 strncpy(longname, cur_dir, namesize);
1076 offset = strlen(cur_dir);
1079 /* Loop through the blocks picking up the name */
1082 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1083 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1087 unfixtarname(longname + offset, buffer_p, MIN(TBLOCK, finfo.size), first--);
1088 DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
1097 static void do_tarput(void)
1100 struct timeval tp_start;
1101 char *longfilename = NULL, linkflag;
1104 GetTimeOfDay(&tp_start);
1105 DEBUG(5, ("RJS do_tarput called ...\n"));
1107 buffer_p = tarbuf + tbufsiz; /* init this to force first read */
1109 /* Now read through those files ... */
1111 /* Get us to the next block, or the first block first time around */
1112 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1113 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1117 DEBUG(5, ("Reading the next header ...\n"));
1119 switch (readtarheader((union hblock *) buffer_p, &finfo, cur_dir)) {
1120 case -2: /* Hmm, not good, but not fatal */
1121 DEBUG(0, ("Skipping %s...\n", finfo.name));
1122 if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) && !skip_file(finfo.size)) {
1123 DEBUG(0, ("Short file, bailing out...\n"));
1129 DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
1132 case 0: /* chksum is zero - looks like an EOF */
1133 DEBUG(0, ("tar: restored %d files and directories\n", ntarf));
1134 return; /* Hmmm, bad here ... */
1141 /* Now, do we have a long file name? */
1142 if (longfilename != NULL) {
1143 SAFE_FREE(finfo.name); /* Free the space already allocated */
1144 finfo.name = longfilename;
1145 longfilename = NULL;
1148 /* Well, now we have a header, process the file ... */
1149 /* Should we skip the file? We have the long name as well here */
1150 skip = clipn && ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl) ||
1152 (tar_re_search && !regexec(preg, finfo.name, 0, NULL, 0)));
1154 (tar_re_search && mask_match(finfo.name, cliplist[0], True)));
1157 DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
1159 skip_file(finfo.size);
1163 /* We only get this far if we should process the file */
1164 linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
1166 case '0': /* Should use symbolic names--FIXME */
1168 * Skip to the next block first, so we can get the file, FIXME, should
1169 * be in get_file ...
1170 * The 'finfo.size != 0' fix is from Bob Boehmer <boehmer@worldnet.att.net>
1171 * Fixes bug where file size in tarfile is zero.
1173 if ((finfo.size != 0) && next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1174 DEBUG(0, ("Short file, bailing out...\n"));
1177 if (!get_file(finfo)) {
1178 DEBUG(0, ("Abandoning restore\n"));
1183 if (!get_dir(finfo)) {
1184 DEBUG(0, ("Abandoning restore \n"));
1189 longfilename = get_longfilename(finfo);
1190 if (!longfilename) {
1191 DEBUG(0, ("abandoning restore\n"));
1194 DEBUG(5, ("Long file name: %s\n", longfilename));
1198 skip_file(finfo.size); /* Don't handle these yet */
1205 * samba interactive commands
1208 /****************************************************************************
1210 ***************************************************************************/
1217 if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1218 DEBUG(0, ("blocksize <n>\n"));
1223 if (block < 0 || block > 65535) {
1224 DEBUG(0, ("blocksize out of range"));
1229 DEBUG(2,("blocksize is now %d\n", blocksize));
1234 /****************************************************************************
1235 command to set incremental / reset mode
1236 ***************************************************************************/
1238 int cmd_tarmode(void)
1242 while (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1243 if (strequal(buf, "full"))
1245 else if (strequal(buf, "inc"))
1247 else if (strequal(buf, "reset"))
1249 else if (strequal(buf, "noreset"))
1251 else if (strequal(buf, "system"))
1253 else if (strequal(buf, "nosystem"))
1255 else if (strequal(buf, "hidden"))
1257 else if (strequal(buf, "nohidden"))
1259 else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
1261 else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
1264 DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
1267 DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
1268 tar_inc ? "incremental" : "full",
1269 tar_system ? "system" : "nosystem",
1270 tar_hidden ? "hidden" : "nohidden",
1271 tar_reset ? "reset" : "noreset",
1272 tar_noisy ? "verbose" : "quiet"));
1276 /****************************************************************************
1277 Feeble attrib command
1278 ***************************************************************************/
1280 int cmd_setmode(void)
1288 attra[0] = attra[1] = 0;
1290 if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1291 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1295 pstrcpy(fname, cur_dir);
1296 pstrcat(fname, buf);
1298 while (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1310 attra[direct]|=aRONLY;
1313 attra[direct]|=aHIDDEN;
1316 attra[direct]|=aSYSTEM;
1319 attra[direct]|=aARCH;
1322 DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1328 if (attra[ATTRSET]==0 && attra[ATTRRESET]==0) {
1329 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1333 DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1334 do_setrattr(fname, attra[ATTRSET], ATTRSET);
1335 do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
1339 /****************************************************************************
1340 Principal command for creating / extracting
1341 ***************************************************************************/
1349 if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1350 DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
1354 argl=toktocliplist(&argcl, NULL);
1355 if (!tar_parseargs(argcl, argl, buf, 0))
1363 /****************************************************************************
1364 Command line (option) version
1365 ***************************************************************************/
1367 int process_tar(void)
1383 if (clipn && tar_excl) {
1387 for (i=0; i<clipn; i++) {
1388 DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
1390 if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1391 *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1394 if (strrchr_m(cliplist[i], '\\')) {
1397 pstrcpy(saved_dir, cur_dir);
1399 if (*cliplist[i]=='\\') {
1400 pstrcpy(tarmac, cliplist[i]);
1402 pstrcpy(tarmac, cur_dir);
1403 pstrcat(tarmac, cliplist[i]);
1405 pstrcpy(cur_dir, tarmac);
1406 *(strrchr_m(cur_dir, '\\')+1)='\0';
1408 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1409 do_list(tarmac,attribute,do_tar, False, True);
1410 pstrcpy(cur_dir,saved_dir);
1412 pstrcpy(tarmac, cur_dir);
1413 pstrcat(tarmac, cliplist[i]);
1414 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1415 do_list(tarmac,attribute,do_tar, False, True);
1420 pstrcpy(mask,cur_dir);
1421 DEBUG(5, ("process_tar, do_list with mask: %s\n", mask));
1422 pstrcat(mask,"\\*");
1423 do_list(mask,attribute,do_tar,False, True);
1427 dotareof(tarhandle);
1431 DEBUG(0, ("tar: dumped %d files and directories\n", ntarf));
1432 DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf));
1436 if (must_free_cliplist) {
1438 for (i = 0; i < clipn; ++i) {
1439 SAFE_FREE(cliplist[i]);
1441 SAFE_FREE(cliplist);
1444 must_free_cliplist = False;
1449 /****************************************************************************
1450 Find a token (filename) in a clip list
1451 ***************************************************************************/
1453 static int clipfind(char **aret, int ret, char *tok)
1458 /* ignore leading slashes or dots in token */
1459 while(strchr_m("/\\.", *tok))
1465 /* ignore leading slashes or dots in list */
1466 while(strchr_m("/\\.", *pkey))
1469 if (!strslashcmp(pkey, tok))
1475 /****************************************************************************
1476 Read list of files to include from the file and initialize cliplist
1478 ***************************************************************************/
1480 static int read_inclusion_file(char *filename)
1482 XFILE *inclusion = NULL;
1483 char buf[PATH_MAX + 1];
1484 char *inclusion_buffer = NULL;
1485 int inclusion_buffer_size = 0;
1486 int inclusion_buffer_sofar = 0;
1493 buf[PATH_MAX] = '\0'; /* guarantee null-termination */
1494 if ((inclusion = x_fopen(filename, O_RDONLY, 0)) == NULL) {
1495 /* XXX It would be better to include a reason for failure, but without
1496 * autoconf, it's hard to use strerror, sys_errlist, etc.
1498 DEBUG(0,("Unable to open inclusion file %s\n", filename));
1502 while ((! error) && (x_fgets(buf, sizeof(buf)-1, inclusion))) {
1503 if (inclusion_buffer == NULL) {
1504 inclusion_buffer_size = 1024;
1505 if ((inclusion_buffer = malloc(inclusion_buffer_size)) == NULL) {
1506 DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1512 if (buf[strlen(buf)-1] == '\n') {
1513 buf[strlen(buf)-1] = '\0';
1516 if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1518 inclusion_buffer_size *= 2;
1519 ib = Realloc(inclusion_buffer,inclusion_buffer_size);
1521 DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1522 inclusion_buffer_size));
1526 inclusion_buffer = ib;
1530 safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
1531 inclusion_buffer_sofar += strlen(buf) + 1;
1534 x_fclose(inclusion);
1537 /* Allocate an array of clipn + 1 char*'s for cliplist */
1538 cliplist = malloc((clipn + 1) * sizeof(char *));
1539 if (cliplist == NULL) {
1540 DEBUG(0,("failure allocating memory for cliplist\n"));
1543 cliplist[clipn] = NULL;
1544 p = inclusion_buffer;
1545 for (i = 0; (! error) && (i < clipn); i++) {
1546 /* set current item to NULL so array will be null-terminated even if
1547 * malloc fails below. */
1549 if ((tmpstr = (char *)malloc(strlen(p)+1)) == NULL) {
1550 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
1553 unfixtarname(tmpstr, p, strlen(p) + 1, True);
1554 cliplist[i] = tmpstr;
1555 if ((p = strchr_m(p, '\000')) == NULL) {
1556 DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1562 must_free_cliplist = True;
1566 SAFE_FREE(inclusion_buffer);
1570 /* We know cliplist is always null-terminated */
1571 for (pp = cliplist; *pp; ++pp) {
1574 SAFE_FREE(cliplist);
1576 must_free_cliplist = False;
1581 /* cliplist and its elements are freed at the end of process_tar. */
1585 /****************************************************************************
1586 Parse tar arguments. Sets tar_type, tar_excl, etc.
1587 ***************************************************************************/
1589 int tar_parseargs(int argc, char *argv[], const char *Optarg, int Optind)
1591 int newOptind = Optind;
1592 char tar_clipfl='\0';
1594 /* Reset back to defaults - could be from interactive version
1595 * reset mode and archive mode left as they are though
1607 if (tar_type=='c') {
1608 printf("Tar must be followed by only one of c or x.\n");
1614 if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1615 DEBUG(0,("Option b must be followed by valid blocksize\n"));
1627 DEBUG(0,("Option N must be followed by valid file name\n"));
1630 SMB_STRUCT_STAT stbuf;
1631 extern time_t newer_than;
1633 if (sys_stat(argv[Optind], &stbuf) == 0) {
1634 newer_than = stbuf.st_mtime;
1635 DEBUG(1,("Getting files newer than %s",
1636 asctime(LocalTime(&newer_than))));
1640 DEBUG(0,("Error setting newer-than time\n"));
1653 DEBUG(0,("Only one of I,X,F must be specified\n"));
1660 DEBUG(0,("Only one of I,X,F must be specified\n"));
1667 DEBUG(0,("Only one of I,X,F must be specified\n"));
1673 DEBUG(0, ("tar_re_search set\n"));
1674 tar_re_search = True;
1677 if (tar_type == 'c') {
1678 DEBUG(0, ("dry_run set\n"));
1681 DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1686 DEBUG(0,("Unknown tar option\n"));
1692 printf("Option T must be followed by one of c or x.\n");
1696 /* tar_excl is true if cliplist lists files to be included.
1697 * Both 'I' and 'F' mean include. */
1698 tar_excl=tar_clipfl!='X';
1700 if (tar_clipfl=='F') {
1701 if (argc-Optind-1 != 1) {
1702 DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1707 if (! read_inclusion_file(argv[Optind])) {
1710 } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
1715 cliplist=argv+Optind+1;
1716 clipn=argc-Optind-1;
1719 if ((tmplist=malloc(clipn*sizeof(char *))) == NULL) {
1720 DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n", clipn));
1724 for (clipcount = 0; clipcount < clipn; clipcount++) {
1726 DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1728 if ((tmpstr = (char *)malloc(strlen(cliplist[clipcount])+1)) == NULL) {
1729 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", clipcount));
1733 unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
1734 tmplist[clipcount] = tmpstr;
1735 DEBUG(5, ("Processed an item, %s\n", tmpstr));
1737 DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1741 must_free_cliplist = True;
1746 if (Optind+1<argc && tar_re_search) { /* Doing regular expression seaches */
1750 if ((preg = (regex_t *)malloc(65536)) == NULL) {
1752 DEBUG(0, ("Could not allocate buffer for regular expression search\n"));
1756 if (errcode = regcomp(preg, argv[Optind + 1], REG_EXTENDED)) {
1760 errlen = regerror(errcode, preg, errstr, sizeof(errstr) - 1);
1761 DEBUG(0, ("Could not compile pattern buffer for re search: %s\n%s\n", argv[Optind + 1], errstr));
1766 clipn=argc-Optind-1;
1767 cliplist=argv+Optind+1;
1771 if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1772 /* Sets tar handle to either 0 or 1, as appropriate */
1773 tarhandle=(tar_type=='c');
1775 * Make sure that dbf points to stderr if we are using stdout for
1778 if (tarhandle == 1) {
1781 if (!argv[Optind]) {
1782 DEBUG(0,("Must specify tar filename\n"));
1785 if (!strcmp(argv[Optind], "-")) {
1790 if (tar_type=='c' && (dry_run || strcmp(argv[Optind], "/dev/null")==0)) {
1792 DEBUG(0,("Output is /dev/null, assuming dry_run\n"));
1796 } else if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1)
1797 || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0)) {
1798 DEBUG(0,("Error opening local file %s - %s\n", argv[Optind], strerror(errno)));