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
52 /* These times are normally kept in GMT */
56 char *name; /* This is dynamically allocate */
58 file_info2 *next, *prev; /* Used in the stack ... */
69 #define SEPARATORS " \t\n\r"
70 extern struct cli_state *cli;
72 /* These defines are for the do_setrattr routine, to indicate
73 * setting and reseting of file attributes in the function call */
77 static uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
79 #ifndef CLIENT_TIMEOUT
80 #define CLIENT_TIMEOUT (30*1000)
83 static char *tarbuf, *buffer_p;
84 static int tp, ntarf, tbufsiz;
86 /* Incremental mode */
87 static BOOL tar_inc=False;
88 /* Reset archive bit */
89 static BOOL tar_reset=False;
90 /* Include / exclude mode (true=include, false=exclude) */
91 static BOOL tar_excl=True;
92 /* use regular expressions for search on file names */
93 static BOOL tar_re_search=False;
97 /* Do not dump anything, just calculate sizes */
98 static BOOL dry_run=False;
99 /* Dump files with System attribute */
100 static BOOL tar_system=True;
101 /* Dump files with Hidden attribute */
102 static BOOL tar_hidden=True;
103 /* Be noisy - make a catalogue */
104 static BOOL tar_noisy=True;
105 static BOOL tar_real_noisy=False; /* Don't want to be really noisy by default */
108 static char **cliplist=NULL;
110 static BOOL must_free_cliplist = False;
112 extern file_info def_finfo;
113 extern BOOL lowercase;
115 extern BOOL readbraw_supported;
117 extern pstring cur_dir;
118 extern int get_total_time_ms;
119 extern int get_total_size;
121 static int blocksize=20;
122 static int tarhandle;
124 static void writetarheader(int f, const char *aname, SMB_BIG_UINT size, time_t mtime,
125 const char *amode, unsigned char ftype);
126 static void do_atar(char *rname,char *lname,file_info *finfo1);
127 static void do_tar(file_info *finfo);
128 static void oct_it(SMB_BIG_UINT value, int ndgs, char *p);
129 static void fixtarname(char *tptr, const char *fp, int l);
130 static int dotarbuf(int f, char *b, int n);
131 static void dozerobuf(int f, int n);
132 static void dotareof(int f);
133 static void initarbuf(void);
135 /* restore functions */
136 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix);
137 static long unoct(char *p, int ndgs);
138 static void do_tarput(void);
139 static void unfixtarname(char *tptr, char *fp, int l, BOOL first);
142 * tar specific utitlities
145 /*******************************************************************
146 Create a string of size size+1 (for the null)
147 *******************************************************************/
148 static char *string_create_s(int size)
152 tmp = (char *)malloc(size+1);
156 DEBUG(0, ("Out of memory in string_create_s\n"));
164 /****************************************************************************
165 Write a tar header to buffer
166 ****************************************************************************/
167 static void writetarheader(int f, const char *aname, SMB_BIG_UINT size, time_t mtime,
168 const char *amode, unsigned char ftype)
174 DEBUG(5, ("WriteTarHdr, Type = %c, Size= %.0f, Name = %s\n", ftype, (double)size, aname));
176 memset(hb.dummy, 0, sizeof(hb.dummy));
179 if (l >= NAMSIZ - 1) {
180 /* write a GNU tar style long header */
182 b = (char *)malloc(l+TBLOCK+100);
184 DEBUG(0,("out of memory\n"));
187 writetarheader(f, "/./@LongLink", l+2, 0, " 0 \0", 'L');
188 memset(b, 0, l+TBLOCK+100);
189 fixtarname(b, aname, l);
191 DEBUG(5, ("File name in tar file: %s, size=%d, \n", b, (int)strlen(b)));
192 dotarbuf(f, b, TBLOCK*(((i-1)/TBLOCK)+1));
196 /* use l + 1 to do the null too */
197 fixtarname(hb.dbuf.name, aname, (l >= NAMSIZ) ? NAMSIZ : l + 1);
200 strlower_m(hb.dbuf.name);
202 /* write out a "standard" tar format header */
204 hb.dbuf.name[NAMSIZ-1]='\0';
205 safe_strcpy(hb.dbuf.mode, amode, sizeof(hb.dbuf.mode)-1);
206 oct_it((SMB_BIG_UINT)0, 8, hb.dbuf.uid);
207 oct_it((SMB_BIG_UINT)0, 8, hb.dbuf.gid);
208 oct_it((SMB_BIG_UINT) size, 13, hb.dbuf.size);
209 if (size > (SMB_BIG_UINT)077777777777LL) {
211 /* This is a non-POSIX compatible extention to store files
214 memset(hb.dbuf.size, 0, 4);
216 for (i = 8, jp=(char*)&size; i; i--)
217 hb.dbuf.size[i+3] = *(jp++);
219 oct_it((SMB_BIG_UINT) mtime, 13, hb.dbuf.mtime);
220 memcpy(hb.dbuf.chksum, " ", sizeof(hb.dbuf.chksum));
221 memset(hb.dbuf.linkname, 0, NAMSIZ);
222 hb.dbuf.linkflag=ftype;
224 for (chk=0, i=sizeof(hb.dummy), jp=hb.dummy; --i>=0;) chk+=(0xFF & *jp++);
226 oct_it((SMB_BIG_UINT) chk, 8, hb.dbuf.chksum);
227 hb.dbuf.chksum[6] = '\0';
229 (void) dotarbuf(f, hb.dummy, sizeof(hb.dummy));
232 /****************************************************************************
233 Read a tar header into a hblock structure, and validate
234 ***************************************************************************/
235 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix)
242 * read in a "standard" tar format header - we're not that interested
243 * in that many fields, though
246 /* check the checksum */
247 for (chk=0, i=sizeof(hb->dummy), jp=hb->dummy; --i>=0;) chk+=(0xFF & *jp++);
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));
265 DEBUG(0, ("checksums don't match %ld %ld\n", fchk, chk));
266 dump_data(5, (char *)hb - TBLOCK, TBLOCK *3);
270 if ((finfo->name = string_create_s(strlen(prefix) + strlen(hb -> dbuf.name) + 3)) == NULL) {
272 DEBUG(0, ("Out of space creating file_info2 for %s\n", hb -> dbuf.name));
277 safe_strcpy(finfo->name, prefix, strlen(prefix) + strlen(hb -> dbuf.name) + 3);
279 /* use l + 1 to do the null too; do prefix - prefcnt to zap leading slash */
280 unfixtarname(finfo->name + strlen(prefix), hb->dbuf.name,
281 strlen(hb->dbuf.name) + 1, True);
283 /* can't handle some links at present */
284 if ((hb->dbuf.linkflag != '0') && (hb -> dbuf.linkflag != '5')) {
285 if (hb->dbuf.linkflag == 0) {
286 DEBUG(6, ("Warning: NULL link flag (gnu tar archive ?) %s\n",
289 if (hb -> dbuf.linkflag == 'L') { /* We have a longlink */
290 /* Do nothing here at the moment. do_tarput will handle this
291 as long as the longlink gets back to it, as it has to advance
292 the buffer pointer, etc */
295 DEBUG(0, ("this tar file appears to contain some kind of link other than a GNUtar Longlink - ignoring\n"));
301 if ((unoct(hb->dbuf.mode, sizeof(hb->dbuf.mode)) & S_IFDIR)
302 || (*(finfo->name+strlen(finfo->name)-1) == '\\'))
307 finfo->mode=0; /* we don't care about mode at the moment, we'll
308 * just make it a regular file */
310 * Bug fix by richard@sj.co.uk
312 * REC: restore times correctly (as does tar)
313 * We only get the modification time of the file; set the creation time
314 * from the mod. time, and the access time to current time
316 finfo->mtime = finfo->ctime = strtol(hb->dbuf.mtime, NULL, 8);
317 finfo->atime = time(NULL);
318 finfo->size = unoct(hb->dbuf.size, sizeof(hb->dbuf.size));
323 /****************************************************************************
324 Write out the tar buffer to tape or wherever
325 ****************************************************************************/
326 static int dotarbuf(int f, char *b, int n)
333 /* This routine and the next one should be the only ones that do write()s */
334 if (tp + n >= tbufsiz)
339 memcpy(tarbuf + tp, b, diff);
340 fail=fail && (1+write(f, tarbuf, tbufsiz));
347 fail=fail && (1 + write(f, b, tbufsiz));
353 memcpy(tarbuf+tp, b, n);
357 return(fail ? writ : 0);
360 /****************************************************************************
361 Write zeros to buffer / tape
362 ****************************************************************************/
363 static void dozerobuf(int f, int n)
365 /* short routine just to write out n zeros to buffer -
366 * used to round files to nearest block
367 * and to do tar EOFs */
374 memset(tarbuf+tp, 0, tbufsiz-tp);
376 write(f, tarbuf, tbufsiz);
377 memset(tarbuf, 0, (tp+=n-tbufsiz));
381 memset(tarbuf+tp, 0, n);
386 /****************************************************************************
388 ****************************************************************************/
389 static void initarbuf(void)
391 /* initialize tar buffer */
392 tbufsiz=blocksize*TBLOCK;
393 tarbuf=malloc(tbufsiz); /* FIXME: We might not get the buffer */
395 /* reset tar buffer pointer and tar file counter and total dumped */
396 tp=0; ntarf=0; ttarf=0;
399 /****************************************************************************
400 Write two zero blocks at end of file
401 ****************************************************************************/
402 static void dotareof(int f)
404 SMB_STRUCT_STAT stbuf;
405 /* Two zero blocks at end of file, write out full buffer */
410 (void) dozerobuf(f, TBLOCK);
411 (void) dozerobuf(f, TBLOCK);
413 if (sys_fstat(f, &stbuf) == -1)
415 DEBUG(0, ("Couldn't stat file handle\n"));
419 /* Could be a pipe, in which case S_ISREG should fail,
420 * and we should write out at full size */
421 if (tp > 0) write(f, tarbuf, S_ISREG(stbuf.st_mode) ? tp : tbufsiz);
424 /****************************************************************************
425 (Un)mangle DOS pathname, make nonabsolute
426 ****************************************************************************/
427 static void fixtarname(char *tptr, const char *fp, int l)
429 /* add a '.' to start of file name, convert from ugly dos \'s in path
430 * to lovely unix /'s :-} */
433 safe_strcpy(tptr, fp, l);
434 string_replace(tptr, '\\', '/');
437 /****************************************************************************
438 Convert from decimal to octal string
439 ****************************************************************************/
440 static void oct_it (SMB_BIG_UINT value, int ndgs, char *p)
442 /* Converts long to octal string, pads with leading zeros */
444 /* skip final null, but do final space */
448 /* Loop does at least one digit */
450 p[--ndgs] = '0' + (char) (value & 7);
453 while (ndgs > 0 && value != 0);
455 /* Do leading zeros */
460 /****************************************************************************
461 Convert from octal string to long
462 ***************************************************************************/
463 static long unoct(char *p, int ndgs)
466 /* Converts octal string to long, ignoring any non-digit */
470 if (isdigit((int)*p))
471 value = (value << 3) | (long) (*p - '0');
479 /****************************************************************************
480 Compare two strings in a slash insensitive way, allowing s1 to match s2
481 if s1 is an "initial" string (up to directory marker). Thus, if s2 is
482 a file in any subdirectory of s1, declare a match.
483 ***************************************************************************/
484 static int strslashcmp(char *s1, char *s2)
490 || tolower(*s1) == tolower(*s2)
491 || (*s1 == '\\' && *s2=='/')
492 || (*s1 == '/' && *s2=='\\'))) {
496 /* if s1 has a trailing slash, it compared equal, so s1 is an "initial"
499 if (!*s1 && s1 != s1_0 && (*(s1-1) == '/' || *(s1-1) == '\\')) return 0;
501 /* ignore trailing slash on s1 */
502 if (!*s2 && (*s1 == '/' || *s1 == '\\') && !*(s1+1)) return 0;
504 /* check for s1 is an "initial" string of s2 */
505 if ((*s2 == '/' || *s2 == '\\') && !*s1) return 0;
511 /****************************************************************************
512 Ensure a remote path exists (make if necessary)
513 ***************************************************************************/
514 static BOOL ensurepath(char *fname)
516 /* *must* be called with buffer ready malloc'ed */
517 /* ensures path exists */
519 char *partpath, *ffname;
520 char *p=fname, *basehack;
522 DEBUG(5, ( "Ensurepath called with: %s\n", fname));
524 partpath = string_create_s(strlen(fname));
525 ffname = string_create_s(strlen(fname));
527 if ((partpath == NULL) || (ffname == NULL)){
529 DEBUG(0, ("Out of memory in ensurepath: %s\n", fname));
536 /* fname copied to ffname so can strtok */
538 safe_strcpy(ffname, fname, strlen(fname));
540 /* do a `basename' on ffname, so don't try and make file name directory */
541 if ((basehack=strrchr_m(ffname, '\\')) == NULL)
546 p=strtok(ffname, "\\");
550 safe_strcat(partpath, p, strlen(fname) + 1);
552 if (!cli_chkpath(cli, partpath)) {
553 if (!cli_mkdir(cli, partpath))
555 DEBUG(0, ("Error mkdirhiering\n"));
559 DEBUG(3, ("mkdirhiering %s\n", partpath));
563 safe_strcat(partpath, "\\", strlen(fname) + 1);
564 p = strtok(NULL,"/\\");
570 static int padit(char *buf, int bufsize, int padsize)
575 DEBUG(5, ("Padding with %d zeros\n", padsize));
576 memset(buf, 0, bufsize);
577 while( !berr && padsize > 0 ) {
578 bytestowrite= MIN(bufsize, padsize);
579 berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite;
580 padsize -= bytestowrite;
587 static void do_setrattr(char *name, uint16 attr, int set)
591 if (!cli_getatr(cli, name, &oldattr, NULL, NULL)) return;
593 if (set == ATTRSET) {
596 attr = oldattr & ~attr;
599 if (!cli_setatr(cli, name, attr, 0)) {
600 DEBUG(1,("setatr failed: %s\n", cli_errstr(cli)));
605 /****************************************************************************
606 append one remote file to the tar file
607 ***************************************************************************/
608 static void do_atar(char *rname,char *lname,file_info *finfo1)
611 SMB_BIG_UINT nread=0;
614 BOOL close_done = False;
615 BOOL shallitime=True;
617 int read_size = 65520;
620 struct timeval tp_start;
621 GetTimeOfDay(&tp_start);
623 ftype = '0'; /* An ordinary file ... */
626 finfo.size = finfo1 -> size;
627 finfo.mode = finfo1 -> mode;
628 finfo.uid = finfo1 -> uid;
629 finfo.gid = finfo1 -> gid;
630 finfo.mtime = finfo1 -> mtime;
631 finfo.atime = finfo1 -> atime;
632 finfo.ctime = finfo1 -> ctime;
633 finfo.name = finfo1 -> name;
636 finfo.size = def_finfo.size;
637 finfo.mode = def_finfo.mode;
638 finfo.uid = def_finfo.uid;
639 finfo.gid = def_finfo.gid;
640 finfo.mtime = def_finfo.mtime;
641 finfo.atime = def_finfo.atime;
642 finfo.ctime = def_finfo.ctime;
643 finfo.name = def_finfo.name;
648 DEBUG(3,("skipping file %s of size %12.0f bytes\n",
650 (double)finfo.size));
652 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
657 fnum = cli_open(cli, rname, O_RDONLY, DENY_NONE);
659 dos_clean_name(rname);
662 DEBUG(0,("%s opening remote file %s (%s)\n",
663 cli_errstr(cli),rname, cur_dir));
667 finfo.name = string_create_s(strlen(rname));
668 if (finfo.name == NULL) {
669 DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n"));
673 safe_strcpy(finfo.name,rname, strlen(rname));
675 if (!cli_getattrE(cli, fnum, &finfo.mode, &finfo.size, NULL, &finfo.atime, &finfo.mtime)) {
676 DEBUG(0, ("getattrE: %s\n", cli_errstr(cli)));
679 finfo.ctime = finfo.mtime;
682 DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
684 if (tar_inc && !(finfo.mode & aARCH))
686 DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
689 else if (!tar_system && (finfo.mode & aSYSTEM))
691 DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
694 else if (!tar_hidden && (finfo.mode & aHIDDEN))
696 DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
701 DEBUG(3,("getting file %s of size %.0f bytes as a tar file %s",
706 /* write a tar header, don't bother with mode - just set to 100644 */
707 writetarheader(tarhandle, rname, finfo.size, finfo.mtime, "100644 \0", ftype);
709 while (nread < finfo.size && !close_done) {
711 DEBUG(3,("nread=%.0f\n",(double)nread));
713 datalen = cli_read(cli, fnum, data, nread, read_size);
716 DEBUG(0,("Error reading file %s : %s\n", rname, cli_errstr(cli)));
722 /* if file size has increased since we made file size query, truncate
723 read so tar header for this file will be correct.
726 if (nread > finfo.size) {
727 datalen -= nread - finfo.size;
728 DEBUG(0,("File size change - truncating %s to %.0f bytes\n", finfo.name, (double)finfo.size));
731 /* add received bits of file to buffer - dotarbuf will
732 * write out in 512 byte intervals */
733 if (dotarbuf(tarhandle,data,datalen) != datalen) {
734 DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
739 DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
746 /* pad tar file with zero's if we couldn't get entire file */
747 if (nread < finfo.size) {
748 DEBUG(0, ("Didn't get entire file. size=%.0f, nread=%d\n", (double)finfo.size, (int)nread));
749 if (padit(data, sizeof(data), finfo.size - nread))
750 DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
753 /* round tar file to nearest block */
754 if (finfo.size % TBLOCK)
755 dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
757 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
761 cli_close(cli, fnum);
765 struct timeval tp_end;
768 /* if shallitime is true then we didn't skip */
769 if (tar_reset && !dry_run)
770 (void) do_setrattr(finfo.name, aARCH, ATTRRESET);
772 GetTimeOfDay(&tp_end);
774 (tp_end.tv_sec - tp_start.tv_sec)*1000 +
775 (tp_end.tv_usec - tp_start.tv_usec)/1000;
776 get_total_time_ms += this_time;
777 get_total_size += finfo.size;
781 DEBUG(0, ("%12.0f (%7.1f kb/s) %s\n",
782 (double)finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
786 /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
787 DEBUG(3,("(%g kb/s) (average %g kb/s)\n",
788 finfo.size / MAX(0.001, (1.024*this_time)),
789 get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
793 /****************************************************************************
794 Append single file to tar file (or not)
795 ***************************************************************************/
796 static void do_tar(file_info *finfo)
800 if (strequal(finfo->name,"..") || strequal(finfo->name,"."))
803 /* Is it on the exclude list ? */
804 if (!tar_excl && clipn) {
807 DEBUG(5, ("Excl: strlen(cur_dir) = %d\n", (int)strlen(cur_dir)));
809 pstrcpy(exclaim, cur_dir);
810 *(exclaim+strlen(exclaim)-1)='\0';
812 pstrcat(exclaim, "\\");
813 pstrcat(exclaim, finfo->name);
815 DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
817 if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
819 (tar_re_search && !regexec(preg, exclaim, 0, NULL, 0))) {
821 (tar_re_search && mask_match(exclaim, cliplist[0], True))) {
823 DEBUG(3,("Skipping file %s\n", exclaim));
828 if (finfo->mode & aDIR)
830 pstring saved_curdir;
833 pstrcpy(saved_curdir, cur_dir);
835 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));
837 pstrcat(cur_dir,finfo->name);
838 pstrcat(cur_dir,"\\");
840 DEBUG(5, ("Writing a dir, Name = %s\n", cur_dir));
842 /* write a tar directory, don't bother with mode - just set it to
844 writetarheader(tarhandle, cur_dir, 0, finfo->mtime, "040755 \0", '5');
846 DEBUG(0,(" directory %s\n", cur_dir));
848 ntarf++; /* Make sure we have a file on there */
849 pstrcpy(mtar_mask,cur_dir);
850 pstrcat(mtar_mask,"*");
851 DEBUG(5, ("Doing list with mtar_mask: %s\n", mtar_mask));
852 do_list(mtar_mask, attribute, do_tar, False, True);
853 pstrcpy(cur_dir,saved_curdir);
857 pstrcpy(rname,cur_dir);
858 pstrcat(rname,finfo->name);
859 do_atar(rname,finfo->name,finfo);
863 /****************************************************************************
864 Convert from UNIX to DOS file names
865 ***************************************************************************/
866 static void unfixtarname(char *tptr, char *fp, int l, BOOL first)
868 /* remove '.' from start of file name, convert from unix /'s to
869 * dos \'s in path. Kill any absolute path names. But only if first!
872 DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
879 if (*fp == '\\' || *fp == '/') {
885 safe_strcpy(tptr, fp, l);
886 string_replace(tptr, '/', '\\');
890 /****************************************************************************
891 Move to the next block in the buffer, which may mean read in another set of
892 blocks. FIXME, we should allow more than one block to be skipped.
893 ****************************************************************************/
894 static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
896 int bufread, total = 0;
898 DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp));
902 if (*bufferp >= (ltarbuf + bufsiz)) {
904 DEBUG(5, ("Reading more data into ltarbuf ...\n"));
907 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>
908 * Fixes bug where read can return short if coming from
912 bufread = read(tarhandle, ltarbuf, bufsiz);
915 while (total < bufsiz) {
916 if (bufread < 0) { /* An error, return false */
917 return (total > 0 ? -2 : bufread);
925 bufread = read(tarhandle, <arbuf[total], bufsiz - total);
929 DEBUG(5, ("Total bytes read ... %i\n", total));
939 /* Skip a file, even if it includes a long file name? */
940 static int skip_file(int skipsize)
942 int dsize = skipsize;
944 DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
946 /* FIXME, we should skip more than one block at a time */
950 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
952 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
964 /*************************************************************
965 Get a file from the tar file and store it.
966 When this is called, tarbuf already contains the first
967 file block. This is a bit broken & needs fixing.
968 **************************************************************/
970 static int get_file(file_info2 finfo)
972 int fnum = -1, pos = 0, dsize = 0, bpos = 0;
973 SMB_BIG_UINT rsize = 0;
975 DEBUG(5, ("get_file: file: %s, size %.0f\n", finfo.name, (double)finfo.size));
977 if (ensurepath(finfo.name) &&
978 (fnum=cli_open(cli, finfo.name, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE)) == -1) {
979 DEBUG(0, ("abandoning restore\n"));
983 /* read the blocks from the tar file and write to the remote file */
985 rsize = finfo.size; /* This is how much to write */
989 /* We can only write up to the end of the buffer */
991 dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, 65520); /* Calculate the size to write */
992 dsize = MIN(dsize, rsize); /* Should be only what is left */
993 DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos));
995 if (cli_write(cli, fnum, 0, buffer_p + bpos, pos, dsize) != dsize) {
996 DEBUG(0, ("Error writing remote file\n"));
1003 /* Now figure out how much to move in the buffer */
1005 /* FIXME, we should skip more than one block at a time */
1007 /* First, skip any initial part of the part written that is left over */
1008 /* from the end of the first TBLOCK */
1010 if ((bpos) && ((bpos + dsize) >= TBLOCK)) {
1012 dsize -= (TBLOCK - bpos); /* Get rid of the end of the first block */
1015 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) { /* and skip the block */
1016 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1024 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>.
1025 * If the file being extracted is an exact multiple of
1026 * TBLOCK bytes then we don't want to extract the next
1027 * block from the tarfile here, as it will be done in
1028 * the caller of get_file().
1031 while (((rsize != 0) && (dsize >= TBLOCK)) ||
1032 ((rsize == 0) && (dsize > TBLOCK))) {
1034 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1035 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1046 /* Now close the file ... */
1048 if (!cli_close(cli, fnum)) {
1049 DEBUG(0, ("Error closing remote file\n"));
1053 /* Now we update the creation date ... */
1055 DEBUG(5, ("Updating creation date on %s\n", finfo.name));
1057 if (!cli_setatr(cli, finfo.name, finfo.mode, finfo.mtime)) {
1058 if (tar_real_noisy) {
1059 DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
1060 /*return(False); */ /* Ignore, as Win95 does not allow changes */
1066 DEBUG(0, ("restore tar file %s of size %.0f bytes\n", finfo.name, (double)finfo.size));
1071 /* Create a directory. We just ensure that the path exists and return as there
1072 is no file associated with a directory
1074 static int get_dir(file_info2 finfo)
1077 DEBUG(0, ("restore directory %s\n", finfo.name));
1079 if (!ensurepath(finfo.name)) {
1081 DEBUG(0, ("Problems creating directory\n"));
1090 /* Get a file with a long file name ... first file has file name, next file
1091 has the data. We only want the long file name, as the loop in do_tarput
1092 will deal with the rest.
1094 static char * get_longfilename(file_info2 finfo)
1096 int namesize = strlen(finfo.name) + strlen(cur_dir) + 2;
1097 char *longname = malloc(namesize);
1098 int offset = 0, left = finfo.size;
1101 DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
1102 DEBUG(5, ("Len = %.0f\n", (double)finfo.size));
1104 if (longname == NULL) {
1106 DEBUG(0, ("could not allocate buffer of size %d for longname\n",
1111 /* First, add cur_dir to the long file name */
1113 if (strlen(cur_dir) > 0) {
1114 strncpy(longname, cur_dir, namesize);
1115 offset = strlen(cur_dir);
1118 /* Loop through the blocks picking up the name */
1122 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1124 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1129 unfixtarname(longname + offset, buffer_p, MIN(TBLOCK, finfo.size), first--);
1130 DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
1141 static void do_tarput(void)
1144 struct timeval tp_start;
1145 char *longfilename = NULL, linkflag;
1148 GetTimeOfDay(&tp_start);
1150 DEBUG(5, ("RJS do_tarput called ...\n"));
1152 buffer_p = tarbuf + tbufsiz; /* init this to force first read */
1154 /* Now read through those files ... */
1158 /* Get us to the next block, or the first block first time around */
1160 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1162 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1168 DEBUG(5, ("Reading the next header ...\n"));
1170 switch (readtarheader((union hblock *) buffer_p, &finfo, cur_dir)) {
1172 case -2: /* Hmm, not good, but not fatal */
1173 DEBUG(0, ("Skipping %s...\n", finfo.name));
1174 if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) &&
1175 !skip_file(finfo.size)) {
1177 DEBUG(0, ("Short file, bailing out...\n"));
1185 DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
1188 case 0: /* chksum is zero - looks like an EOF */
1189 DEBUG(0, ("tar: restored %d files and directories\n", ntarf));
1190 return; /* Hmmm, bad here ... */
1199 /* Now, do we have a long file name? */
1201 if (longfilename != NULL) {
1203 SAFE_FREE(finfo.name); /* Free the space already allocated */
1204 finfo.name = longfilename;
1205 longfilename = NULL;
1209 /* Well, now we have a header, process the file ... */
1211 /* Should we skip the file? We have the long name as well here */
1214 ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl)
1216 || (tar_re_search && !regexec(preg, finfo.name, 0, NULL, 0)));
1218 || (tar_re_search && mask_match(finfo.name, cliplist[0], True)));
1221 DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
1225 skip_file(finfo.size);
1230 /* We only get this far if we should process the file */
1231 linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
1235 case '0': /* Should use symbolic names--FIXME */
1238 * Skip to the next block first, so we can get the file, FIXME, should
1239 * be in get_file ...
1240 * The 'finfo.size != 0' fix is from Bob Boehmer <boehmer@worldnet.att.net>
1241 * Fixes bug where file size in tarfile is zero.
1244 if ((finfo.size != 0) && next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1245 DEBUG(0, ("Short file, bailing out...\n"));
1248 if (!get_file(finfo)) {
1249 DEBUG(0, ("Abandoning restore\n"));
1256 if (!get_dir(finfo)) {
1257 DEBUG(0, ("Abandoning restore \n"));
1263 longfilename = get_longfilename(finfo);
1264 if (!longfilename) {
1265 DEBUG(0, ("abandoning restore\n"));
1269 DEBUG(5, ("Long file name: %s\n", longfilename));
1273 skip_file(finfo.size); /* Don't handle these yet */
1285 * samba interactive commands
1288 /****************************************************************************
1290 ***************************************************************************/
1296 if (!next_token_nr(NULL,buf,NULL,sizeof(buf)))
1298 DEBUG(0, ("blocksize <n>\n"));
1303 if (block < 0 || block > 65535)
1305 DEBUG(0, ("blocksize out of range"));
1310 DEBUG(2,("blocksize is now %d\n", blocksize));
1315 /****************************************************************************
1316 command to set incremental / reset mode
1317 ***************************************************************************/
1318 int cmd_tarmode(void)
1322 while (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1323 if (strequal(buf, "full"))
1325 else if (strequal(buf, "inc"))
1327 else if (strequal(buf, "reset"))
1329 else if (strequal(buf, "noreset"))
1331 else if (strequal(buf, "system"))
1333 else if (strequal(buf, "nosystem"))
1335 else if (strequal(buf, "hidden"))
1337 else if (strequal(buf, "nohidden"))
1339 else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
1341 else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
1343 else DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
1346 DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
1347 tar_inc ? "incremental" : "full",
1348 tar_system ? "system" : "nosystem",
1349 tar_hidden ? "hidden" : "nohidden",
1350 tar_reset ? "reset" : "noreset",
1351 tar_noisy ? "verbose" : "quiet"));
1356 /****************************************************************************
1357 Feeble attrib command
1358 ***************************************************************************/
1359 int cmd_setmode(void)
1367 attra[0] = attra[1] = 0;
1369 if (!next_token_nr(NULL,buf,NULL,sizeof(buf)))
1371 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1375 pstrcpy(fname, cur_dir);
1376 pstrcat(fname, buf);
1378 while (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1387 case 'r': attra[direct]|=aRONLY;
1389 case 'h': attra[direct]|=aHIDDEN;
1391 case 's': attra[direct]|=aSYSTEM;
1393 case 'a': attra[direct]|=aARCH;
1395 default: DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1400 if (attra[ATTRSET]==0 && attra[ATTRRESET]==0)
1402 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1406 DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1407 do_setrattr(fname, attra[ATTRSET], ATTRSET);
1408 do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
1413 /****************************************************************************
1414 Principal command for creating / extracting
1415 ***************************************************************************/
1422 if (!next_token_nr(NULL,buf,NULL,sizeof(buf)))
1424 DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
1428 argl=toktocliplist(&argcl, NULL);
1429 if (!tar_parseargs(argcl, argl, buf, 0))
1439 /****************************************************************************
1440 Command line (option) version
1441 ***************************************************************************/
1442 int process_tar(void)
1458 if (clipn && tar_excl) {
1462 for (i=0; i<clipn; i++) {
1463 DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
1465 if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1466 *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1469 if (strrchr_m(cliplist[i], '\\')) {
1472 pstrcpy(saved_dir, cur_dir);
1474 if (*cliplist[i]=='\\') {
1475 pstrcpy(tarmac, cliplist[i]);
1477 pstrcpy(tarmac, cur_dir);
1478 pstrcat(tarmac, cliplist[i]);
1480 pstrcpy(cur_dir, tarmac);
1481 *(strrchr_m(cur_dir, '\\')+1)='\0';
1483 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1484 do_list(tarmac,attribute,do_tar, False, True);
1485 pstrcpy(cur_dir,saved_dir);
1487 pstrcpy(tarmac, cur_dir);
1488 pstrcat(tarmac, cliplist[i]);
1489 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1490 do_list(tarmac,attribute,do_tar, False, True);
1495 pstrcpy(mask,cur_dir);
1496 DEBUG(5, ("process_tar, do_list with mask: %s\n", mask));
1497 pstrcat(mask,"\\*");
1498 do_list(mask,attribute,do_tar,False, True);
1501 if (ntarf) dotareof(tarhandle);
1505 DEBUG(0, ("tar: dumped %d files and directories\n", ntarf));
1506 DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf));
1510 if (must_free_cliplist) {
1512 for (i = 0; i < clipn; ++i) {
1513 SAFE_FREE(cliplist[i]);
1515 SAFE_FREE(cliplist);
1518 must_free_cliplist = False;
1524 /****************************************************************************
1525 Find a token (filename) in a clip list
1526 ***************************************************************************/
1527 static int clipfind(char **aret, int ret, char *tok)
1529 if (aret==NULL) return 0;
1531 /* ignore leading slashes or dots in token */
1532 while(strchr_m("/\\.", *tok)) tok++;
1537 /* ignore leading slashes or dots in list */
1538 while(strchr_m("/\\.", *pkey)) pkey++;
1540 if (!strslashcmp(pkey, tok)) return 1;
1546 /****************************************************************************
1547 Read list of files to include from the file and initialize cliplist
1549 ***************************************************************************/
1550 static int read_inclusion_file(char *filename)
1552 XFILE *inclusion = NULL;
1553 char buf[MAXPATHLEN + 1];
1554 char *inclusion_buffer = NULL;
1555 int inclusion_buffer_size = 0;
1556 int inclusion_buffer_sofar = 0;
1563 buf[MAXPATHLEN] = '\0'; /* guarantee null-termination */
1564 if ((inclusion = x_fopen(filename, O_RDONLY, 0)) == NULL) {
1565 /* XXX It would be better to include a reason for failure, but without
1566 * autoconf, it's hard to use strerror, sys_errlist, etc.
1568 DEBUG(0,("Unable to open inclusion file %s\n", filename));
1572 while ((! error) && (x_fgets(buf, sizeof(buf)-1, inclusion))) {
1573 if (inclusion_buffer == NULL) {
1574 inclusion_buffer_size = 1024;
1575 if ((inclusion_buffer = malloc(inclusion_buffer_size)) == NULL) {
1576 DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1582 if (buf[strlen(buf)-1] == '\n') {
1583 buf[strlen(buf)-1] = '\0';
1586 if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1588 inclusion_buffer_size *= 2;
1589 ib = Realloc(inclusion_buffer,inclusion_buffer_size);
1591 DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1592 inclusion_buffer_size));
1596 else inclusion_buffer = ib;
1599 safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
1600 inclusion_buffer_sofar += strlen(buf) + 1;
1603 x_fclose(inclusion);
1606 /* Allocate an array of clipn + 1 char*'s for cliplist */
1607 cliplist = malloc((clipn + 1) * sizeof(char *));
1608 if (cliplist == NULL) {
1609 DEBUG(0,("failure allocating memory for cliplist\n"));
1612 cliplist[clipn] = NULL;
1613 p = inclusion_buffer;
1614 for (i = 0; (! error) && (i < clipn); i++) {
1615 /* set current item to NULL so array will be null-terminated even if
1616 * malloc fails below. */
1618 if ((tmpstr = (char *)malloc(strlen(p)+1)) == NULL) {
1619 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
1622 unfixtarname(tmpstr, p, strlen(p) + 1, True);
1623 cliplist[i] = tmpstr;
1624 if ((p = strchr_m(p, '\000')) == NULL) {
1625 DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1631 must_free_cliplist = True;
1635 SAFE_FREE(inclusion_buffer);
1639 /* We know cliplist is always null-terminated */
1640 for (pp = cliplist; *pp; ++pp) {
1643 SAFE_FREE(cliplist);
1645 must_free_cliplist = False;
1650 /* cliplist and its elements are freed at the end of process_tar. */
1654 /****************************************************************************
1655 Parse tar arguments. Sets tar_type, tar_excl, etc.
1656 ***************************************************************************/
1657 int tar_parseargs(int argc, char *argv[], char *Optarg, int Optind)
1659 char tar_clipfl='\0';
1661 /* Reset back to defaults - could be from interactive version
1662 * reset mode and archive mode left as they are though
1674 if (tar_type=='c') {
1675 printf("Tar must be followed by only one of c or x.\n");
1681 if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1682 DEBUG(0,("Option b must be followed by valid blocksize\n"));
1693 DEBUG(0,("Option N must be followed by valid file name\n"));
1696 SMB_STRUCT_STAT stbuf;
1697 extern time_t newer_than;
1699 if (sys_stat(argv[Optind], &stbuf) == 0) {
1700 newer_than = stbuf.st_mtime;
1701 DEBUG(1,("Getting files newer than %s",
1702 asctime(LocalTime(&newer_than))));
1705 DEBUG(0,("Error setting newer-than time\n"));
1718 DEBUG(0,("Only one of I,X,F must be specified\n"));
1725 DEBUG(0,("Only one of I,X,F must be specified\n"));
1732 DEBUG(0,("Only one of I,X,F must be specified\n"));
1738 DEBUG(0, ("tar_re_search set\n"));
1739 tar_re_search = True;
1742 if (tar_type == 'c') {
1743 DEBUG(0, ("dry_run set\n"));
1746 DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1751 DEBUG(0,("Unknown tar option\n"));
1756 printf("Option T must be followed by one of c or x.\n");
1760 /* tar_excl is true if cliplist lists files to be included.
1761 * Both 'I' and 'F' mean include. */
1762 tar_excl=tar_clipfl!='X';
1764 if (tar_clipfl=='F') {
1765 if (argc-Optind-1 != 1) {
1766 DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1769 if (! read_inclusion_file(argv[Optind+1])) {
1772 } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
1777 cliplist=argv+Optind+1;
1778 clipn=argc-Optind-1;
1781 if ((tmplist=malloc(clipn*sizeof(char *))) == NULL) {
1782 DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n",
1788 for (clipcount = 0; clipcount < clipn; clipcount++) {
1790 DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1792 if ((tmpstr = (char *)malloc(strlen(cliplist[clipcount])+1)) == NULL) {
1793 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n",
1798 unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
1799 tmplist[clipcount] = tmpstr;
1800 DEBUG(5, ("Processed an item, %s\n", tmpstr));
1802 DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1805 must_free_cliplist = True;
1808 if (Optind+1<argc && tar_re_search) { /* Doing regular expression seaches */
1812 if ((preg = (regex_t *)malloc(65536)) == NULL) {
1814 DEBUG(0, ("Could not allocate buffer for regular expression search\n"));
1819 if (errcode = regcomp(preg, argv[Optind + 1], REG_EXTENDED)) {
1823 errlen = regerror(errcode, preg, errstr, sizeof(errstr) - 1);
1825 DEBUG(0, ("Could not compile pattern buffer for re search: %s\n%s\n", argv[Optind + 1], errstr));
1831 clipn=argc-Optind-1;
1832 cliplist=argv+Optind+1;
1836 if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1837 /* Sets tar handle to either 0 or 1, as appropriate */
1838 tarhandle=(tar_type=='c');
1840 * Make sure that dbf points to stderr if we are using stdout for
1846 if (tar_type=='c' && (dry_run || strcmp(argv[Optind], "/dev/null")==0))
1849 DEBUG(0,("Output is /dev/null, assuming dry_run\n"));
1854 if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1)
1855 || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0))
1857 DEBUG(0,("Error opening local file %s - %s\n",
1858 argv[Optind], strerror(errno)));