2 Unix SMB/Netbios implementation.
5 Copyright (C) Ricky Poulten 1995-1998
6 Copyright (C) Richard Sharpe 1998
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 /* The following changes developed by Richard Sharpe for Canon Information
23 Systems Research Australia (CISRA)
25 1. Restore can now restore files with long file names
26 2. Save now saves directory information so that we can restore
27 directory creation times
28 3. tar now accepts both UNIX path names and DOS path names. I prefer
29 those lovely /'s to those UGLY \'s :-)
30 4. the files to exclude can be specified as a regular expression by adding
31 an r flag to the other tar flags. Eg:
33 -TcrX file.tar "*.(obj|exe)"
35 will skip all .obj and .exe files
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 stack dir_stack = {NULL, 0}; /* Want an empty stack */
71 #define SEPARATORS " \t\n\r"
72 extern int DEBUGLEVEL;
73 extern struct cli_state *cli;
75 /* These defines are for the do_setrattr routine, to indicate
76 * setting and reseting of file attributes in the function call */
80 static uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
82 #ifndef CLIENT_TIMEOUT
83 #define CLIENT_TIMEOUT (30*1000)
86 static char *tarbuf, *buffer_p;
87 static int tp, ntarf, tbufsiz, ttarf;
88 /* Incremental mode */
90 /* Reset archive bit */
92 /* Include / exclude mode (true=include, false=exclude) */
94 /* use regular expressions for search on file names */
95 BOOL tar_re_search=False;
99 /* Do not dump anything, just calculate sizes */
101 /* Dump files with System attribute */
102 BOOL tar_system=True;
103 /* Dump files with Hidden attribute */
104 BOOL tar_hidden=True;
105 /* Be noisy - make a catalogue */
107 BOOL tar_real_noisy=False; /* Don't want to be really noisy by default */
110 static char **cliplist=NULL;
112 static BOOL must_free_cliplist = False;
114 extern file_info def_finfo;
115 extern BOOL lowercase;
117 extern BOOL readbraw_supported;
119 extern pstring cur_dir;
120 extern int get_total_time_ms;
121 extern int get_total_size;
127 static void writetarheader(int f, char *aname, int size, time_t mtime,
128 char *amode, unsigned char ftype);
129 static void do_atar(char *rname,char *lname,file_info *finfo1);
130 static void do_tar(file_info *finfo);
131 static void oct_it(long value, int ndgs, char *p);
132 static void fixtarname(char *tptr, char *fp, int l);
133 static int dotarbuf(int f, char *b, int n);
134 static void dozerobuf(int f, int n);
135 static void dotareof(int f);
136 static void initarbuf(void);
138 /* restore functions */
139 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix);
140 static long unoct(char *p, int ndgs);
141 static void do_tarput(void);
142 static void unfixtarname(char *tptr, char *fp, int l, BOOL first);
145 * tar specific utitlities
148 /*******************************************************************
149 Create a string of size size+1 (for the null)
150 *******************************************************************/
151 static char *string_create_s(int size)
155 tmp = (char *)malloc(size+1);
159 DEBUG(0, ("Out of memory in string_create_s\n"));
167 /****************************************************************************
168 Write a tar header to buffer
169 ****************************************************************************/
170 static void writetarheader(int f, char *aname, int size, time_t mtime,
171 char *amode, unsigned char ftype)
177 DEBUG(5, ("WriteTarHdr, Type = %c, Size= %i, Name = %s\n", ftype, size, aname));
179 memset(hb.dummy, 0, sizeof(hb.dummy));
183 /* write a GNU tar style long header */
185 b = (char *)malloc(l+TBLOCK+100);
187 DEBUG(0,("out of memory\n"));
190 writetarheader(f, "/./@LongLink", l+1, 0, " 0 \0", 'L');
191 memset(b, 0, l+TBLOCK+100);
192 fixtarname(b, aname, l);
194 DEBUG(5, ("File name in tar file: %s, size=%i, \n", b, strlen(b)));
195 dotarbuf(f, b, TBLOCK*(((i-1)/TBLOCK)+1));
199 /* use l + 1 to do the null too */
200 fixtarname(hb.dbuf.name, aname, (l >= NAMSIZ) ? NAMSIZ : l + 1);
203 strlower(hb.dbuf.name);
205 /* write out a "standard" tar format header */
207 hb.dbuf.name[NAMSIZ-1]='\0';
208 safe_strcpy(hb.dbuf.mode, amode, strlen(amode));
209 oct_it(0L, 8, hb.dbuf.uid);
210 oct_it(0L, 8, hb.dbuf.gid);
211 oct_it((long) size, 13, hb.dbuf.size);
212 oct_it((long) mtime, 13, hb.dbuf.mtime);
213 memcpy(hb.dbuf.chksum, " ", sizeof(hb.dbuf.chksum));
214 memset(hb.dbuf.linkname, 0, NAMSIZ);
215 hb.dbuf.linkflag=ftype;
217 for (chk=0, i=sizeof(hb.dummy), jp=hb.dummy; --i>=0;) chk+=(0xFF & *jp++);
219 oct_it((long) chk, 8, hb.dbuf.chksum);
220 hb.dbuf.chksum[6] = '\0';
222 (void) dotarbuf(f, hb.dummy, sizeof(hb.dummy));
225 /****************************************************************************
226 Read a tar header into a hblock structure, and validate
227 ***************************************************************************/
228 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix)
235 * read in a "standard" tar format header - we're not that interested
236 * in that many fields, though
239 /* check the checksum */
240 for (chk=0, i=sizeof(hb->dummy), jp=hb->dummy; --i>=0;) chk+=(0xFF & *jp++);
245 /* compensate for blanks in chksum header */
246 for (i=sizeof(hb->dbuf.chksum), jp=hb->dbuf.chksum; --i>=0;)
249 chk += ' ' * sizeof(hb->dbuf.chksum);
251 fchk=unoct(hb->dbuf.chksum, sizeof(hb->dbuf.chksum));
253 DEBUG(5, ("checksum totals chk=%ld fchk=%ld chksum=%s\n",
254 chk, fchk, hb->dbuf.chksum));
258 DEBUG(0, ("checksums don't match %ld %ld\n", fchk, chk));
259 dump_data(5, (char *)hb - TBLOCK, TBLOCK *3);
263 if ((finfo->name = string_create_s(strlen(prefix) + strlen(hb -> dbuf.name) + 3)) == NULL) {
265 DEBUG(0, ("Out of space creating file_info2 for %s\n", hb -> dbuf.name));
270 safe_strcpy(finfo->name, prefix, strlen(prefix) + strlen(hb -> dbuf.name) + 3);
272 /* use l + 1 to do the null too; do prefix - prefcnt to zap leading slash */
273 unfixtarname(finfo->name + strlen(prefix), hb->dbuf.name,
274 strlen(hb->dbuf.name) + 1, True);
276 /* can't handle some links at present */
277 if ((hb->dbuf.linkflag != '0') && (hb -> dbuf.linkflag != '5')) {
278 if (hb->dbuf.linkflag == 0) {
279 DEBUG(6, ("Warning: NULL link flag (gnu tar archive ?) %s\n",
282 if (hb -> dbuf.linkflag == 'L') { /* We have a longlink */
283 /* Do nothing here at the moment. do_tarput will handle this
284 as long as the longlink gets back to it, as it has to advance
285 the buffer pointer, etc */
288 DEBUG(0, ("this tar file appears to contain some kind of link other than a GNUtar Longlink - ignoring\n"));
294 if ((unoct(hb->dbuf.mode, sizeof(hb->dbuf.mode)) & S_IFDIR)
295 || (*(finfo->name+strlen(finfo->name)-1) == '\\'))
300 finfo->mode=0; /* we don't care about mode at the moment, we'll
301 * just make it a regular file */
303 * Bug fix by richard@sj.co.uk
305 * REC: restore times correctly (as does tar)
306 * We only get the modification time of the file; set the creation time
307 * from the mod. time, and the access time to current time
309 finfo->mtime = finfo->ctime = strtol(hb->dbuf.mtime, NULL, 8);
310 finfo->atime = time(NULL);
311 finfo->size = unoct(hb->dbuf.size, sizeof(hb->dbuf.size));
316 /****************************************************************************
317 Write out the tar buffer to tape or wherever
318 ****************************************************************************/
319 static int dotarbuf(int f, char *b, int n)
326 /* This routine and the next one should be the only ones that do write()s */
327 if (tp + n >= tbufsiz)
332 memcpy(tarbuf + tp, b, diff);
333 fail=fail && (1+write(f, tarbuf, tbufsiz));
340 fail=fail && (1 + write(f, b, tbufsiz));
346 memcpy(tarbuf+tp, b, n);
350 return(fail ? writ : 0);
353 /****************************************************************************
354 Write zeros to buffer / tape
355 ****************************************************************************/
356 static void dozerobuf(int f, int n)
358 /* short routine just to write out n zeros to buffer -
359 * used to round files to nearest block
360 * and to do tar EOFs */
367 memset(tarbuf+tp, 0, tbufsiz-tp);
369 write(f, tarbuf, tbufsiz);
370 memset(tarbuf, 0, (tp+=n-tbufsiz));
374 memset(tarbuf+tp, 0, n);
379 /****************************************************************************
381 ****************************************************************************/
382 static void initarbuf(void)
384 /* initialize tar buffer */
385 tbufsiz=blocksize*TBLOCK;
386 tarbuf=malloc(tbufsiz); /* FIXME: We might not get the buffer */
388 /* reset tar buffer pointer and tar file counter and total dumped */
389 tp=0; ntarf=0; ttarf=0;
392 /****************************************************************************
393 Write two zero blocks at end of file
394 ****************************************************************************/
395 static void dotareof(int f)
397 SMB_STRUCT_STAT stbuf;
398 /* Two zero blocks at end of file, write out full buffer */
403 (void) dozerobuf(f, TBLOCK);
404 (void) dozerobuf(f, TBLOCK);
406 if (sys_fstat(f, &stbuf) == -1)
408 DEBUG(0, ("Couldn't stat file handle\n"));
412 /* Could be a pipe, in which case S_ISREG should fail,
413 * and we should write out at full size */
414 if (tp > 0) write(f, tarbuf, S_ISREG(stbuf.st_mode) ? tp : tbufsiz);
417 /****************************************************************************
418 (Un)mangle DOS pathname, make nonabsolute
419 ****************************************************************************/
420 static void fixtarname(char *tptr, char *fp, int l)
422 /* add a '.' to start of file name, convert from ugly dos \'s in path
423 * to lovely unix /'s :-} */
429 if((skip = skip_multibyte_char( *fp)) != 0) {
434 } else if (skip == 1) {
438 } else if (*fp == '\\') {
449 /****************************************************************************
450 Convert from decimal to octal string
451 ****************************************************************************/
452 static void oct_it (long value, int ndgs, char *p)
454 /* Converts long to octal string, pads with leading zeros */
456 /* skip final null, but do final space */
460 /* Loop does at least one digit */
462 p[--ndgs] = '0' + (char) (value & 7);
465 while (ndgs > 0 && value != 0);
467 /* Do leading zeros */
472 /****************************************************************************
473 Convert from octal string to long
474 ***************************************************************************/
475 static long unoct(char *p, int ndgs)
478 /* Converts octal string to long, ignoring any non-digit */
482 if (isdigit((int)*p))
483 value = (value << 3) | (long) (*p - '0');
491 /****************************************************************************
492 Compare two strings in a slash insensitive way, allowing s1 to match s2
493 if s1 is an "initial" string (up to directory marker). Thus, if s2 is
494 a file in any subdirectory of s1, declare a match.
495 ***************************************************************************/
496 static int strslashcmp(char *s1, char *s2)
502 || tolower(*s1) == tolower(*s2)
503 || (*s1 == '\\' && *s2=='/')
504 || (*s1 == '/' && *s2=='\\'))) {
508 /* if s1 has a trailing slash, it compared equal, so s1 is an "initial"
511 if (!*s1 && s1 != s1_0 && (*(s1-1) == '/' || *(s1-1) == '\\')) return 0;
513 /* ignore trailing slash on s1 */
514 if (!*s2 && (*s1 == '/' || *s1 == '\\') && !*(s1+1)) return 0;
516 /* check for s1 is an "initial" string of s2 */
517 if (*s2 == '/' || *s2 == '\\') return 0;
523 /****************************************************************************
524 Ensure a remote path exists (make if necessary)
525 ***************************************************************************/
526 static BOOL ensurepath(char *fname)
528 /* *must* be called with buffer ready malloc'ed */
529 /* ensures path exists */
531 char *partpath, *ffname;
532 char *p=fname, *basehack;
534 DEBUG(5, ( "Ensurepath called with: %s\n", fname));
536 partpath = string_create_s(strlen(fname));
537 ffname = string_create_s(strlen(fname));
539 if ((partpath == NULL) || (ffname == NULL)){
541 DEBUG(0, ("Out of memory in ensurepath: %s\n", fname));
548 /* fname copied to ffname so can strtok */
550 safe_strcpy(ffname, fname, strlen(fname));
552 /* do a `basename' on ffname, so don't try and make file name directory */
553 if ((basehack=strrchr(ffname, '\\')) == NULL)
558 p=strtok(ffname, "\\");
562 safe_strcat(partpath, p, strlen(fname) + 1);
564 if (!cli_chkpath(cli, partpath)) {
565 if (!cli_mkdir(cli, partpath))
567 DEBUG(0, ("Error mkdirhiering\n"));
571 DEBUG(3, ("mkdirhiering %s\n", partpath));
575 safe_strcat(partpath, "\\", strlen(fname) + 1);
576 p = strtok(NULL,"/\\");
582 static int padit(char *buf, int bufsize, int padsize)
587 DEBUG(5, ("Padding with %d zeros\n", padsize));
588 memset(buf, 0, bufsize);
589 while( !berr && padsize > 0 ) {
590 bytestowrite= MIN(bufsize, padsize);
591 berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite;
592 padsize -= bytestowrite;
599 static void do_setrattr(char *name, uint16 attr, int set)
603 if (!cli_getatr(cli, name, &oldattr, NULL, NULL)) return;
605 if (set == ATTRSET) {
608 attr = oldattr & ~attr;
611 if (!cli_setatr(cli, name, attr, 0)) {
612 DEBUG(1,("setatr failed: %s\n", cli_errstr(cli)));
617 /****************************************************************************
618 append one remote file to the tar file
619 ***************************************************************************/
620 static void do_atar(char *rname,char *lname,file_info *finfo1)
626 BOOL close_done = False;
627 BOOL shallitime=True;
629 int read_size = 65520;
632 struct timeval tp_start;
633 GetTimeOfDay(&tp_start);
635 ftype = '0'; /* An ordinary file ... */
638 finfo.size = finfo1 -> size;
639 finfo.mode = finfo1 -> mode;
640 finfo.uid = finfo1 -> uid;
641 finfo.gid = finfo1 -> gid;
642 finfo.mtime = finfo1 -> mtime;
643 finfo.atime = finfo1 -> atime;
644 finfo.ctime = finfo1 -> ctime;
647 finfo.size = def_finfo.size;
648 finfo.mode = def_finfo.mode;
649 finfo.uid = def_finfo.uid;
650 finfo.gid = def_finfo.gid;
651 finfo.mtime = def_finfo.mtime;
652 finfo.atime = def_finfo.atime;
653 finfo.ctime = def_finfo.ctime;
658 DEBUG(3,("skipping file %s of size %d bytes\n",
662 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
667 fnum = cli_open(cli, rname, O_RDONLY, DENY_NONE);
669 dos_clean_name(rname);
672 DEBUG(0,("%s opening remote file %s (%s)\n",
673 cli_errstr(cli),rname, cur_dir));
677 finfo.name = string_create_s(strlen(rname));
678 if (finfo.name == NULL) {
679 DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n"));
683 safe_strcpy(finfo.name,rname, strlen(rname));
685 if (!cli_getattrE(cli, fnum, &finfo.mode, &finfo.size, NULL, &finfo.atime, &finfo.mtime)) {
686 DEBUG(0, ("getattrE: %s\n", cli_errstr(cli)));
689 finfo.ctime = finfo.mtime;
692 DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
694 if (tar_inc && !(finfo.mode & aARCH))
696 DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
699 else if (!tar_system && (finfo.mode & aSYSTEM))
701 DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
704 else if (!tar_hidden && (finfo.mode & aHIDDEN))
706 DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
711 DEBUG(3,("getting file %s of size %d bytes as a tar file %s",
716 /* write a tar header, don't bother with mode - just set to 100644 */
717 writetarheader(tarhandle, rname, finfo.size, finfo.mtime, "100644 \0", ftype);
719 while (nread < finfo.size && !close_done) {
721 DEBUG(3,("nread=%d\n",nread));
723 datalen = cli_read(cli, fnum, data, nread, read_size);
726 DEBUG(0,("Error reading file %s : %s\n", rname, cli_errstr(cli)));
730 /* add received bits of file to buffer - dotarbuf will
731 * write out in 512 byte intervals */
732 if (dotarbuf(tarhandle,data,datalen) != datalen) {
733 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=%d, nread=%d\n", finfo.size, 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, ("%10d (%7.1f kb/s) %s\n",
782 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) = %i\n", strlen(cur_dir)));
809 safe_strcpy(exclaim, cur_dir, sizeof(pstring));
810 *(exclaim+strlen(exclaim)-1)='\0';
812 safe_strcat(exclaim, "\\", sizeof(pstring));
813 safe_strcat(exclaim, finfo->name, sizeof(exclaim));
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, False))) {
823 DEBUG(3,("Skipping file %s\n", exclaim));
828 if (finfo->mode & aDIR)
830 pstring saved_curdir;
833 safe_strcpy(saved_curdir, cur_dir, sizeof(saved_curdir));
835 DEBUG(5, ("Sizeof(cur_dir)=%i, strlen(cur_dir)=%i, strlen(finfo->name)=%i\nname=%s,cur_dir=%s\n", sizeof(cur_dir), strlen(cur_dir), strlen(finfo->name), finfo->name, cur_dir));
837 safe_strcat(cur_dir,finfo->name, sizeof(cur_dir));
838 safe_strcat(cur_dir,"\\", sizeof(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 safe_strcpy(mtar_mask,cur_dir, sizeof(pstring));
850 safe_strcat(mtar_mask,"*", sizeof(pstring));
851 do_list(mtar_mask, attribute, do_tar, False, True);
852 safe_strcpy(cur_dir,saved_curdir, sizeof(pstring));
856 safe_strcpy(rname,cur_dir, sizeof(pstring));
857 safe_strcat(rname,finfo->name, sizeof(pstring));
858 do_atar(rname,finfo->name,finfo);
862 /****************************************************************************
863 Convert from UNIX to DOS file names
864 ***************************************************************************/
865 static void unfixtarname(char *tptr, char *fp, int l, BOOL first)
867 /* remove '.' from start of file name, convert from unix /'s to
868 * dos \'s in path. Kill any absolute path names. But only if first!
871 DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
878 if (*fp == '\\' || *fp == '/') {
886 if(( skip = skip_multibyte_char( *fp )) != 0) {
891 } else if (skip == 1) {
895 } else if (*fp == '/') {
907 /****************************************************************************
908 Move to the next block in the buffer, which may mean read in another set of
909 blocks. FIXME, we should allow more than one block to be skipped.
910 ****************************************************************************/
911 static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
913 int bufread, total = 0;
915 DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp));
919 if (*bufferp >= (ltarbuf + bufsiz)) {
921 DEBUG(5, ("Reading more data into ltarbuf ...\n"));
925 for (bufread = read(tarhandle, ltarbuf, bufsiz); total < bufsiz; total += bufread) {
927 if (bufread <= 0) { /* An error, return false */
928 return (total > 0 ? -2 : bufread);
933 DEBUG(5, ("Total bytes read ... %i\n", total));
943 /* Skip a file, even if it includes a long file name? */
944 static int skip_file(int skipsize)
946 int dsize = skipsize;
948 DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
950 /* FIXME, we should skip more than one block at a time */
954 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
956 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
968 /* We get a file from the tar file and store it */
969 static int get_file(file_info2 finfo)
971 int fsize = finfo.size;
972 int fnum = -1, pos = 0, dsize = 0, rsize = 0, bpos = 0;
974 DEBUG(5, ("get_file: file: %s, size %i\n", finfo.name, fsize));
976 if (ensurepath(finfo.name) &&
977 (fnum=cli_open(cli, finfo.name, O_WRONLY|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 = fsize; /* 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)));
1023 while (dsize >= TBLOCK) {
1025 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1027 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1040 /* Now close the file ... */
1042 if (!cli_close(cli, fnum)) {
1043 DEBUG(0, ("Error closing remote file\n"));
1047 /* Now we update the creation date ... */
1049 DEBUG(5, ("Updating creation date on %s\n", finfo.name));
1051 if (!cli_setatr(cli, finfo.name, finfo.mode, finfo.mtime)) {
1052 if (tar_real_noisy) {
1053 DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
1054 /*return(False); */ /* Ignore, as Win95 does not allow changes */
1060 DEBUG(0, ("restore tar file %s of size %d bytes\n", finfo.name, finfo.size));
1065 /* Create a directory. We just ensure that the path exists and return as there
1066 is no file associated with a directory
1068 static int get_dir(file_info2 finfo)
1071 DEBUG(5, ("Creating directory: %s\n", finfo.name));
1073 if (!ensurepath(finfo.name)) {
1075 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 = %i\n", finfo.size));
1096 if (longname == NULL) {
1098 DEBUG(0, ("could not allocate buffer of size %d for longname\n",
1099 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, ("total of %d tar files restored to share\n", ntarf));
1182 return; /* Hmmm, bad here ... */
1191 /* Now, do we have a long file name? */
1193 if (longfilename != NULL) {
1195 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(finfo.name, cliplist[0], True, False)));
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 */
1229 /* Skip to the next block first, so we can get the file, FIXME, should
1230 be in get_file ... */
1232 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1233 DEBUG(0, ("Short file, bailing out...\n"));
1236 if (!get_file(finfo)) {
1237 DEBUG(0, ("Abandoning restore\n"));
1244 if (!get_dir(finfo)) {
1245 DEBUG(0, ("Abandoning restore \n"));
1251 longfilename = get_longfilename(finfo);
1252 if (!longfilename) {
1253 DEBUG(0, ("abandoning restore\n"));
1257 DEBUG(5, ("Long file name: %s\n", longfilename));
1261 skip_file(finfo.size); /* Don't handle these yet */
1273 * samba interactive commands
1276 /****************************************************************************
1278 ***************************************************************************/
1279 void cmd_block(void)
1284 if (!next_token(NULL,buf,NULL,sizeof(buf)))
1286 DEBUG(0, ("blocksize <n>\n"));
1291 if (block < 0 || block > 65535)
1293 DEBUG(0, ("blocksize out of range"));
1298 DEBUG(2,("blocksize is now %d\n", blocksize));
1301 /****************************************************************************
1302 command to set incremental / reset mode
1303 ***************************************************************************/
1304 void cmd_tarmode(void)
1308 while (next_token(NULL,buf,NULL,sizeof(buf))) {
1309 if (strequal(buf, "full"))
1311 else if (strequal(buf, "inc"))
1313 else if (strequal(buf, "reset"))
1315 else if (strequal(buf, "noreset"))
1317 else if (strequal(buf, "system"))
1319 else if (strequal(buf, "nosystem"))
1321 else if (strequal(buf, "hidden"))
1323 else if (strequal(buf, "nohidden"))
1325 else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
1327 else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
1329 else DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
1332 DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
1333 tar_inc ? "incremental" : "full",
1334 tar_system ? "system" : "nosystem",
1335 tar_hidden ? "hidden" : "nohidden",
1336 tar_reset ? "reset" : "noreset",
1337 tar_noisy ? "verbose" : "quiet"));
1341 /****************************************************************************
1342 Feeble attrib command
1343 ***************************************************************************/
1344 void cmd_setmode(void)
1352 attra[0] = attra[1] = 0;
1354 if (!next_token(NULL,buf,NULL,sizeof(buf)))
1356 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1360 safe_strcpy(fname, cur_dir, sizeof(pstring));
1361 safe_strcat(fname, buf, sizeof(pstring));
1363 while (next_token(NULL,buf,NULL,sizeof(buf))) {
1372 case 'r': attra[direct]|=aRONLY;
1374 case 'h': attra[direct]|=aHIDDEN;
1376 case 's': attra[direct]|=aSYSTEM;
1378 case 'a': attra[direct]|=aARCH;
1380 default: DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1385 if (attra[ATTRSET]==0 && attra[ATTRRESET]==0)
1387 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1391 DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1392 do_setrattr(fname, attra[ATTRSET], ATTRSET);
1393 do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
1396 /****************************************************************************
1397 Principal command for creating / extracting
1398 ***************************************************************************/
1405 if (!next_token(NULL,buf,NULL,sizeof(buf)))
1407 DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
1411 argl=toktocliplist(&argcl, NULL);
1412 if (!tar_parseargs(argcl, argl, buf, 0))
1420 /****************************************************************************
1421 Command line (option) version
1422 ***************************************************************************/
1423 int process_tar(void)
1439 if (clipn && tar_excl) {
1443 for (i=0; i<clipn; i++) {
1444 DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
1446 if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1447 *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1450 if (strrchr(cliplist[i], '\\')) {
1453 safe_strcpy(saved_dir, cur_dir, sizeof(pstring));
1455 if (*cliplist[i]=='\\') {
1456 safe_strcpy(tarmac, cliplist[i], sizeof(pstring));
1458 safe_strcpy(tarmac, cur_dir, sizeof(pstring));
1459 safe_strcat(tarmac, cliplist[i], sizeof(pstring));
1461 safe_strcpy(cur_dir, tarmac, sizeof(pstring));
1462 *(strrchr(cur_dir, '\\')+1)='\0';
1464 do_list(tarmac,attribute,do_tar, False, True);
1465 safe_strcpy(cur_dir,saved_dir, sizeof(pstring));
1467 safe_strcpy(tarmac, cur_dir, sizeof(pstring));
1468 safe_strcat(tarmac, cliplist[i], sizeof(pstring));
1469 do_list(tarmac,attribute,do_tar, False, True);
1474 safe_strcpy(mask,cur_dir, sizeof(pstring));
1475 safe_strcat(mask,"\\*", sizeof(pstring));
1476 do_list(mask,attribute,do_tar,False, True);
1479 if (ntarf) dotareof(tarhandle);
1483 DEBUG(0, ("tar: dumped %d tar files\n", ntarf));
1484 DEBUG(0, ("Total bytes written: %d\n", ttarf));
1488 if (must_free_cliplist) {
1490 for (i = 0; i < clipn; ++i) {
1496 must_free_cliplist = False;
1502 /****************************************************************************
1503 Find a token (filename) in a clip list
1504 ***************************************************************************/
1505 static int clipfind(char **aret, int ret, char *tok)
1507 if (aret==NULL) return 0;
1509 /* ignore leading slashes or dots in token */
1510 while(strchr("/\\.", *tok)) tok++;
1515 /* ignore leading slashes or dots in list */
1516 while(strchr("/\\.", *pkey)) pkey++;
1518 if (!strslashcmp(pkey, tok)) return 1;
1524 /****************************************************************************
1525 Read list of files to include from the file and initialize cliplist
1527 ***************************************************************************/
1528 static int read_inclusion_file(char *filename)
1530 FILE *inclusion = NULL;
1531 char buf[MAXPATHLEN + 1];
1532 char *inclusion_buffer = NULL;
1533 int inclusion_buffer_size = 0;
1534 int inclusion_buffer_sofar = 0;
1541 buf[MAXPATHLEN] = '\0'; /* guarantee null-termination */
1542 if ((inclusion = sys_fopen(filename, "r")) == NULL) {
1543 /* XXX It would be better to include a reason for failure, but without
1544 * autoconf, it's hard to use strerror, sys_errlist, etc.
1546 DEBUG(0,("Unable to open inclusion file %s\n", filename));
1550 while ((! error) && (fgets(buf, sizeof(buf)-1, inclusion))) {
1551 if (inclusion_buffer == NULL) {
1552 inclusion_buffer_size = 1024;
1553 if ((inclusion_buffer = malloc(inclusion_buffer_size)) == NULL) {
1554 DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1560 if (buf[strlen(buf)-1] == '\n') {
1561 buf[strlen(buf)-1] = '\0';
1564 if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1565 inclusion_buffer_size *= 2;
1566 inclusion_buffer = Realloc(inclusion_buffer,inclusion_buffer_size);
1567 if (! inclusion_buffer) {
1568 DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1569 inclusion_buffer_size));
1575 safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
1576 inclusion_buffer_sofar += strlen(buf) + 1;
1582 /* Allocate an array of clipn + 1 char*'s for cliplist */
1583 cliplist = malloc((clipn + 1) * sizeof(char *));
1584 if (cliplist == NULL) {
1585 DEBUG(0,("failure allocating memory for cliplist\n"));
1588 cliplist[clipn] = NULL;
1589 p = inclusion_buffer;
1590 for (i = 0; (! error) && (i < clipn); i++) {
1591 /* set current item to NULL so array will be null-terminated even if
1592 * malloc fails below. */
1594 if ((tmpstr = (char *)malloc(strlen(p)+1)) == NULL) {
1595 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
1598 unfixtarname(tmpstr, p, strlen(p) + 1, True);
1599 cliplist[i] = tmpstr;
1600 if ((p = strchr(p, '\000')) == NULL) {
1601 DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1607 must_free_cliplist = True;
1611 if (inclusion_buffer) {
1612 free(inclusion_buffer);
1617 /* We know cliplist is always null-terminated */
1618 for (pp = cliplist; *pp; ++pp) {
1623 must_free_cliplist = False;
1628 /* cliplist and its elements are freed at the end of process_tar. */
1632 /****************************************************************************
1633 Parse tar arguments. Sets tar_type, tar_excl, etc.
1634 ***************************************************************************/
1635 int tar_parseargs(int argc, char *argv[], char *Optarg, int Optind)
1637 char tar_clipfl='\0';
1639 /* Reset back to defaults - could be from interactive version
1640 * reset mode and archive mode left as they are though
1652 if (tar_type=='c') {
1653 printf("Tar must be followed by only one of c or x.\n");
1659 if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1660 DEBUG(0,("Option b must be followed by valid blocksize\n"));
1671 DEBUG(0,("Option N must be followed by valid file name\n"));
1674 SMB_STRUCT_STAT stbuf;
1675 extern time_t newer_than;
1677 if (dos_stat(argv[Optind], &stbuf) == 0) {
1678 newer_than = stbuf.st_mtime;
1679 DEBUG(1,("Getting files newer than %s",
1680 asctime(LocalTime(&newer_than))));
1683 DEBUG(0,("Error setting newer-than time\n"));
1696 DEBUG(0,("Only one of I,X,F must be specified\n"));
1703 DEBUG(0,("Only one of I,X,F must be specified\n"));
1710 DEBUG(0,("Only one of I,X,F must be specified\n"));
1716 DEBUG(0, ("tar_re_search set\n"));
1717 tar_re_search = True;
1720 if (tar_type == 'c') {
1721 DEBUG(0, ("dry_run set\n"));
1724 DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1729 DEBUG(0,("Unknown tar option\n"));
1734 printf("Option T must be followed by one of c or x.\n");
1738 /* tar_excl is true if cliplist lists files to be included.
1739 * Both 'I' and 'F' mean include. */
1740 tar_excl=tar_clipfl!='X';
1742 if (tar_clipfl=='F') {
1743 if (argc-Optind-1 != 1) {
1744 DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1747 if (! read_inclusion_file(argv[Optind+1])) {
1750 } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
1755 cliplist=argv+Optind+1;
1756 clipn=argc-Optind-1;
1759 if ((tmplist=malloc(clipn*sizeof(char *))) == NULL) {
1760 DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n",
1766 for (clipcount = 0; clipcount < clipn; clipcount++) {
1768 DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1770 if ((tmpstr = (char *)malloc(strlen(cliplist[clipcount])+1)) == NULL) {
1771 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n",
1776 unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
1777 tmplist[clipcount] = tmpstr;
1778 DEBUG(5, ("Processed an item, %s\n", tmpstr));
1780 DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1783 must_free_cliplist = True;
1786 if (Optind+1<argc && tar_re_search) { /* Doing regular expression seaches */
1790 if ((preg = (regex_t *)malloc(65536)) == NULL) {
1792 DEBUG(0, ("Could not allocate buffer for regular expression search\n"));
1797 if (errcode = regcomp(preg, argv[Optind + 1], REG_EXTENDED)) {
1801 errlen = regerror(errcode, preg, errstr, sizeof(errstr) - 1);
1803 DEBUG(0, ("Could not compile pattern buffer for re search: %s\n%s\n", argv[Optind + 1], errstr));
1809 clipn=argc-Optind-1;
1810 cliplist=argv+Optind+1;
1814 if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1815 /* Sets tar handle to either 0 or 1, as appropriate */
1816 tarhandle=(tar_type=='c');
1818 if (tar_type=='c' && (dry_run || strcmp(argv[Optind], "/dev/null")==0))
1821 DEBUG(0,("Output is /dev/null, assuming dry_run"));
1826 if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1)
1827 || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0))
1829 DEBUG(0,("Error opening local file %s - %s\n",
1830 argv[Optind], strerror(errno)));