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)
604 if (!cli_getatr(cli, name, &oldattr, NULL, &t)) return;
606 if (set == ATTRSET) {
609 attr = oldattr & ~attr;
612 if (!cli_setatr(cli, name, attr, t)) {
613 DEBUG(1,("setatr failed: %s\n", cli_errstr(cli)));
618 /****************************************************************************
619 append one remote file to the tar file
620 ***************************************************************************/
621 static void do_atar(char *rname,char *lname,file_info *finfo1)
627 BOOL close_done = False;
628 BOOL shallitime=True;
630 int read_size = 65520;
633 struct timeval tp_start;
634 GetTimeOfDay(&tp_start);
636 ftype = '0'; /* An ordinary file ... */
639 finfo.size = finfo1 -> size;
640 finfo.mode = finfo1 -> mode;
641 finfo.uid = finfo1 -> uid;
642 finfo.gid = finfo1 -> gid;
643 finfo.mtime = finfo1 -> mtime;
644 finfo.atime = finfo1 -> atime;
645 finfo.ctime = finfo1 -> ctime;
648 finfo.size = def_finfo.size;
649 finfo.mode = def_finfo.mode;
650 finfo.uid = def_finfo.uid;
651 finfo.gid = def_finfo.gid;
652 finfo.mtime = def_finfo.mtime;
653 finfo.atime = def_finfo.atime;
654 finfo.ctime = def_finfo.ctime;
659 DEBUG(3,("skipping file %s of size %d bytes\n",
663 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
668 fnum = cli_open(cli, rname, O_RDONLY, DENY_NONE);
670 dos_clean_name(rname);
673 DEBUG(0,("%s opening remote file %s (%s)\n",
674 cli_errstr(cli),rname, cur_dir));
678 finfo.name = string_create_s(strlen(rname));
679 if (finfo.name == NULL) {
680 DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n"));
684 safe_strcpy(finfo.name,rname, strlen(rname));
686 if (!cli_getattrE(cli, fnum, &finfo.mode, &finfo.size, NULL, &finfo.atime, &finfo.mtime)) {
687 DEBUG(0, ("getattrE: %s\n", cli_errstr(cli)));
690 finfo.ctime = finfo.mtime;
693 DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
695 if (tar_inc && !(finfo.mode & aARCH))
697 DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
700 else if (!tar_system && (finfo.mode & aSYSTEM))
702 DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
705 else if (!tar_hidden && (finfo.mode & aHIDDEN))
707 DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
712 DEBUG(3,("getting file %s of size %d bytes as a tar file %s",
717 /* write a tar header, don't bother with mode - just set to 100644 */
718 writetarheader(tarhandle, rname, finfo.size, finfo.mtime, "100644 \0", ftype);
720 while (nread < finfo.size && !close_done) {
722 DEBUG(3,("nread=%d\n",nread));
724 datalen = cli_read(cli, fnum, data, nread, read_size);
727 DEBUG(0,("Error reading file %s : %s\n", rname, cli_errstr(cli)));
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)));
740 DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
747 /* pad tar file with zero's if we couldn't get entire file */
748 if (nread < finfo.size) {
749 DEBUG(0, ("Didn't get entire file. size=%d, nread=%d\n", finfo.size, nread));
750 if (padit(data, sizeof(data), finfo.size - nread))
751 DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
754 /* round tar file to nearest block */
755 if (finfo.size % TBLOCK)
756 dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
758 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
762 cli_close(cli, fnum);
766 struct timeval tp_end;
769 /* if shallitime is true then we didn't skip */
770 if (tar_reset && !dry_run)
771 (void) do_setrattr(finfo.name, aARCH, ATTRRESET);
773 GetTimeOfDay(&tp_end);
775 (tp_end.tv_sec - tp_start.tv_sec)*1000 +
776 (tp_end.tv_usec - tp_start.tv_usec)/1000;
777 get_total_time_ms += this_time;
778 get_total_size += finfo.size;
782 DEBUG(0, ("%10d (%7.1f kb/s) %s\n",
783 finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
787 /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
788 DEBUG(3,("(%g kb/s) (average %g kb/s)\n",
789 finfo.size / MAX(0.001, (1.024*this_time)),
790 get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
794 /****************************************************************************
795 Append single file to tar file (or not)
796 ***************************************************************************/
797 static void do_tar(file_info *finfo)
801 if (strequal(finfo->name,"..") || strequal(finfo->name,"."))
804 /* Is it on the exclude list ? */
805 if (!tar_excl && clipn) {
808 DEBUG(5, ("Excl: strlen(cur_dir) = %i\n", strlen(cur_dir)));
810 safe_strcpy(exclaim, cur_dir, sizeof(pstring));
811 *(exclaim+strlen(exclaim)-1)='\0';
813 safe_strcat(exclaim, "\\", sizeof(pstring));
814 safe_strcat(exclaim, finfo->name, sizeof(exclaim));
816 DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
818 if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
820 (tar_re_search && !regexec(preg, exclaim, 0, NULL, 0))) {
822 (tar_re_search && mask_match(exclaim, cliplist[0], True, False))) {
824 DEBUG(3,("Skipping file %s\n", exclaim));
829 if (finfo->mode & aDIR)
831 pstring saved_curdir;
834 safe_strcpy(saved_curdir, cur_dir, sizeof(saved_curdir));
836 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));
838 safe_strcat(cur_dir,finfo->name, sizeof(cur_dir));
839 safe_strcat(cur_dir,"\\", sizeof(cur_dir));
841 DEBUG(5, ("Writing a dir, Name = %s\n", cur_dir));
843 /* write a tar directory, don't bother with mode - just set it to
845 writetarheader(tarhandle, cur_dir, 0, finfo->mtime, "040755 \0", '5');
847 DEBUG(0,(" directory %s\n", cur_dir));
849 ntarf++; /* Make sure we have a file on there */
850 safe_strcpy(mtar_mask,cur_dir, sizeof(pstring));
851 safe_strcat(mtar_mask,"*.*", sizeof(pstring));
852 do_list(mtar_mask, attribute, do_tar, False, True);
853 safe_strcpy(cur_dir,saved_curdir, sizeof(pstring));
857 safe_strcpy(rname,cur_dir, sizeof(pstring));
858 safe_strcat(rname,finfo->name, sizeof(pstring));
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 == '/') {
887 if(( skip = skip_multibyte_char( *fp )) != 0) {
892 } else if (skip == 1) {
896 } else if (*fp == '/') {
908 /****************************************************************************
909 Move to the next block in the buffer, which may mean read in another set of
910 blocks. FIXME, we should allow more than one block to be skipped.
911 ****************************************************************************/
912 static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
914 int bufread, total = 0;
916 DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp));
920 if (*bufferp >= (ltarbuf + bufsiz)) {
922 DEBUG(5, ("Reading more data into ltarbuf ...\n"));
926 for (bufread = read(tarhandle, ltarbuf, bufsiz); total < bufsiz; total += bufread) {
928 if (bufread <= 0) { /* An error, return false */
929 return (total > 0 ? -2 : bufread);
934 DEBUG(5, ("Total bytes read ... %i\n", total));
944 /* Skip a file, even if it includes a long file name? */
945 static int skip_file(int skipsize)
947 int dsize = skipsize;
949 DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
951 /* FIXME, we should skip more than one block at a time */
955 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
957 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
969 /* We get a file from the tar file and store it */
970 static int get_file(file_info2 finfo)
972 int fsize = finfo.size;
973 int fnum, pos = 0, dsize = 0, rsize = 0, bpos = 0;
975 DEBUG(5, ("get_file: file: %s, size %i\n", finfo.name, fsize));
977 if (ensurepath(finfo.name) &&
978 (fnum=cli_open(cli, finfo.name, O_WRONLY|O_CREAT|O_TRUNC, DENY_NONE)) == -1)
980 DEBUG(0, ("abandoning restore\n"));
984 /* read the blocks from the tar file and write to the remote file */
986 rsize = fsize; /* This is how much to write */
990 /* We can only write up to the end of the buffer */
992 dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, 65520); /* Calculate the size to write */
993 dsize = MIN(dsize, rsize); /* Should be only what is left */
994 DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos));
996 if (cli_write(cli, fnum, 0, buffer_p + bpos, pos, dsize) != dsize) {
997 DEBUG(0, ("Error writing remote file\n"));
1004 /* Now figure out how much to move in the buffer */
1006 /* FIXME, we should skip more than one block at a time */
1008 /* First, skip any initial part of the part written that is left over */
1009 /* from the end of the first TBLOCK */
1011 if ((bpos) && ((bpos + dsize) >= TBLOCK)) {
1013 dsize -= (TBLOCK - bpos); /* Get rid of the end of the first block */
1016 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) { /* and skip the block */
1017 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1024 while (dsize >= TBLOCK) {
1026 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1028 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1041 /* Now close the file ... */
1043 if (!cli_close(cli, fnum)) {
1044 DEBUG(0, ("Error closing remote file\n"));
1048 /* Now we update the creation date ... */
1050 DEBUG(5, ("Updating creation date on %s\n", finfo.name));
1052 if (!cli_setatr(cli, finfo.name, finfo.mode, finfo.mtime)) {
1053 if (tar_real_noisy) {
1054 DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
1055 /*return(False); */ /* Ignore, as Win95 does not allow changes */
1061 DEBUG(0, ("restore tar file %s of size %d bytes\n", finfo.name, finfo.size));
1066 /* Create a directory. We just ensure that the path exists and return as there
1067 is no file associated with a directory
1069 static int get_dir(file_info2 finfo)
1072 DEBUG(5, ("Creating directory: %s\n", finfo.name));
1074 if (!ensurepath(finfo.name)) {
1076 DEBUG(0, ("Problems creating directory\n"));
1083 /* Get a file with a long file name ... first file has file name, next file
1084 has the data. We only want the long file name, as the loop in do_tarput
1085 will deal with the rest.
1087 static char * get_longfilename(file_info2 finfo)
1089 int namesize = finfo.size + strlen(cur_dir) + 2;
1090 char *longname = malloc(namesize);
1091 int offset = 0, left = finfo.size;
1094 DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
1095 DEBUG(5, ("Len = %i\n", finfo.size));
1097 if (longname == NULL) {
1099 DEBUG(0, ("could not allocate buffer of size %d for longname\n",
1100 finfo.size + strlen(cur_dir) + 2));
1104 /* First, add cur_dir to the long file name */
1106 if (strlen(cur_dir) > 0) {
1107 strncpy(longname, cur_dir, namesize);
1108 offset = strlen(cur_dir);
1111 /* Loop through the blocks picking up the name */
1115 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1117 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1122 unfixtarname(longname + offset, buffer_p, MIN(TBLOCK, finfo.size), first--);
1123 DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
1134 static void do_tarput(void)
1137 struct timeval tp_start;
1138 char *longfilename = NULL, linkflag;
1141 GetTimeOfDay(&tp_start);
1143 DEBUG(5, ("RJS do_tarput called ...\n"));
1145 buffer_p = tarbuf + tbufsiz; /* init this to force first read */
1147 /* Now read through those files ... */
1151 /* Get us to the next block, or the first block first time around */
1153 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1155 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1161 DEBUG(5, ("Reading the next header ...\n"));
1163 switch (readtarheader((union hblock *) buffer_p, &finfo, cur_dir)) {
1165 case -2: /* Hmm, not good, but not fatal */
1166 DEBUG(0, ("Skipping %s...\n", finfo.name));
1167 if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) &&
1168 !skip_file(finfo.size)) {
1170 DEBUG(0, ("Short file, bailing out...\n"));
1178 DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
1181 case 0: /* chksum is zero - looks like an EOF */
1182 DEBUG(0, ("total of %d tar files restored to share\n", ntarf));
1183 return; /* Hmmm, bad here ... */
1192 /* Now, do we have a long file name? */
1194 if (longfilename != NULL) {
1196 free(finfo.name); /* Free the space already allocated */
1197 finfo.name = longfilename;
1198 longfilename = NULL;
1202 /* Well, now we have a header, process the file ... */
1204 /* Should we skip the file? We have the long name as well here */
1207 ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl)
1209 || (tar_re_search && !regexec(preg, finfo.name, 0, NULL, 0)));
1211 || (tar_re_search && mask_match(finfo.name, cliplist[0], True, False)));
1214 DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
1218 skip_file(finfo.size);
1223 /* We only get this far if we should process the file */
1224 linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
1228 case '0': /* Should use symbolic names--FIXME */
1230 /* Skip to the next block first, so we can get the file, FIXME, should
1231 be in get_file ... */
1233 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1234 DEBUG(0, ("Short file, bailing out...\n"));
1237 if (!get_file(finfo)) {
1238 DEBUG(0, ("Abandoning restore\n"));
1245 if (!get_dir(finfo)) {
1246 DEBUG(0, ("Abandoning restore \n"));
1252 longfilename = get_longfilename(finfo);
1253 if (!longfilename) {
1254 DEBUG(0, ("abandoning restore\n"));
1258 DEBUG(5, ("Long file name: %s\n", longfilename));
1262 skip_file(finfo.size); /* Don't handle these yet */
1274 * samba interactive commands
1277 /****************************************************************************
1279 ***************************************************************************/
1280 void cmd_block(void)
1285 if (!next_token(NULL,buf,NULL,sizeof(buf)))
1287 DEBUG(0, ("blocksize <n>\n"));
1292 if (block < 0 || block > 65535)
1294 DEBUG(0, ("blocksize out of range"));
1299 DEBUG(2,("blocksize is now %d\n", blocksize));
1302 /****************************************************************************
1303 command to set incremental / reset mode
1304 ***************************************************************************/
1305 void cmd_tarmode(void)
1309 while (next_token(NULL,buf,NULL,sizeof(buf))) {
1310 if (strequal(buf, "full"))
1312 else if (strequal(buf, "inc"))
1314 else if (strequal(buf, "reset"))
1316 else if (strequal(buf, "noreset"))
1318 else if (strequal(buf, "system"))
1320 else if (strequal(buf, "nosystem"))
1322 else if (strequal(buf, "hidden"))
1324 else if (strequal(buf, "nohidden"))
1326 else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
1328 else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
1330 else DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
1333 DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
1334 tar_inc ? "incremental" : "full",
1335 tar_system ? "system" : "nosystem",
1336 tar_hidden ? "hidden" : "nohidden",
1337 tar_reset ? "reset" : "noreset",
1338 tar_noisy ? "verbose" : "quiet"));
1342 /****************************************************************************
1343 Feeble attrib command
1344 ***************************************************************************/
1345 void cmd_setmode(void)
1353 attra[0] = attra[1] = 0;
1355 if (!next_token(NULL,buf,NULL,sizeof(buf)))
1357 DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1361 safe_strcpy(fname, cur_dir, sizeof(pstring));
1362 safe_strcat(fname, buf, sizeof(pstring));
1364 while (next_token(NULL,buf,NULL,sizeof(buf))) {
1373 case 'r': attra[direct]|=aRONLY;
1375 case 'h': attra[direct]|=aHIDDEN;
1377 case 's': attra[direct]|=aSYSTEM;
1379 case 'a': attra[direct]|=aARCH;
1381 default: DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1386 if (attra[ATTRSET]==0 && attra[ATTRRESET]==0)
1388 DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1392 DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1393 (void) do_setrattr(fname, attra[ATTRSET], ATTRSET);
1394 (void) do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
1397 /****************************************************************************
1398 Principal command for creating / extracting
1399 ***************************************************************************/
1406 if (!next_token(NULL,buf,NULL,sizeof(buf)))
1408 DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
1412 argl=toktocliplist(&argcl, NULL);
1413 if (!tar_parseargs(argcl, argl, buf, 0))
1421 /****************************************************************************
1422 Command line (option) version
1423 ***************************************************************************/
1424 int process_tar(void)
1440 if (clipn && tar_excl) {
1444 for (i=0; i<clipn; i++) {
1445 DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
1447 if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1448 *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1451 if (strrchr(cliplist[i], '\\')) {
1454 safe_strcpy(saved_dir, cur_dir, sizeof(pstring));
1456 if (*cliplist[i]=='\\') {
1457 safe_strcpy(tarmac, cliplist[i], sizeof(pstring));
1459 safe_strcpy(tarmac, cur_dir, sizeof(pstring));
1460 safe_strcat(tarmac, cliplist[i], sizeof(pstring));
1462 safe_strcpy(cur_dir, tarmac, sizeof(pstring));
1463 *(strrchr(cur_dir, '\\')+1)='\0';
1465 do_list(tarmac,attribute,do_tar, False, True);
1466 safe_strcpy(cur_dir,saved_dir, sizeof(pstring));
1468 safe_strcpy(tarmac, cur_dir, sizeof(pstring));
1469 safe_strcat(tarmac, cliplist[i], sizeof(pstring));
1470 do_list(tarmac,attribute,do_tar, False, True);
1475 safe_strcpy(mask,cur_dir, sizeof(pstring));
1476 safe_strcat(mask,"\\*.*", sizeof(pstring));
1477 do_list(mask,attribute,do_tar,False, True);
1480 if (ntarf) dotareof(tarhandle);
1484 DEBUG(0, ("tar: dumped %d tar files\n", ntarf));
1485 DEBUG(0, ("Total bytes written: %d\n", ttarf));
1489 if (must_free_cliplist) {
1491 for (i = 0; i < clipn; ++i) {
1497 must_free_cliplist = False;
1503 /****************************************************************************
1504 Find a token (filename) in a clip list
1505 ***************************************************************************/
1506 static int clipfind(char **aret, int ret, char *tok)
1508 if (aret==NULL) return 0;
1510 /* ignore leading slashes or dots in token */
1511 while(strchr("/\\.", *tok)) tok++;
1516 /* ignore leading slashes or dots in list */
1517 while(strchr("/\\.", *pkey)) pkey++;
1519 if (!strslashcmp(pkey, tok)) return 1;
1525 /****************************************************************************
1526 Read list of files to include from the file and initialize cliplist
1528 ***************************************************************************/
1529 static int read_inclusion_file(char *filename)
1531 FILE *inclusion = NULL;
1532 char buf[MAXPATHLEN + 1];
1533 char *inclusion_buffer = NULL;
1534 int inclusion_buffer_size = 0;
1535 int inclusion_buffer_sofar = 0;
1542 buf[MAXPATHLEN] = '\0'; /* guarantee null-termination */
1543 if ((inclusion = fopen(filename, "r")) == NULL) {
1544 /* XXX It would be better to include a reason for failure, but without
1545 * autoconf, it's hard to use strerror, sys_errlist, etc.
1547 DEBUG(0,("Unable to open inclusion file %s\n", filename));
1551 while ((! error) && (fgets(buf, sizeof(buf)-1, inclusion))) {
1552 if (inclusion_buffer == NULL) {
1553 inclusion_buffer_size = 1024;
1554 if ((inclusion_buffer = malloc(inclusion_buffer_size)) == NULL) {
1555 DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1561 if (buf[strlen(buf)-1] == '\n') {
1562 buf[strlen(buf)-1] = '\0';
1565 if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1566 inclusion_buffer_size *= 2;
1567 inclusion_buffer = Realloc(inclusion_buffer,inclusion_buffer_size);
1568 if (! inclusion_buffer) {
1569 DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1570 inclusion_buffer_size));
1576 safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
1577 inclusion_buffer_sofar += strlen(buf) + 1;
1583 /* Allocate an array of clipn + 1 char*'s for cliplist */
1584 cliplist = malloc((clipn + 1) * sizeof(char *));
1585 if (cliplist == NULL) {
1586 DEBUG(0,("failure allocating memory for cliplist\n"));
1589 cliplist[clipn] = NULL;
1590 p = inclusion_buffer;
1591 for (i = 0; (! error) && (i < clipn); i++) {
1592 /* set current item to NULL so array will be null-terminated even if
1593 * malloc fails below. */
1595 if ((tmpstr = (char *)malloc(strlen(p)+1)) == NULL) {
1596 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
1599 unfixtarname(tmpstr, p, strlen(p) + 1, True);
1600 cliplist[i] = tmpstr;
1601 if ((p = strchr(p, '\000')) == NULL) {
1602 DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1608 must_free_cliplist = True;
1612 if (inclusion_buffer) {
1613 free(inclusion_buffer);
1618 /* We know cliplist is always null-terminated */
1619 for (pp = cliplist; *pp; ++pp) {
1624 must_free_cliplist = False;
1629 /* cliplist and its elements are freed at the end of process_tar. */
1633 /****************************************************************************
1634 Parse tar arguments. Sets tar_type, tar_excl, etc.
1635 ***************************************************************************/
1636 int tar_parseargs(int argc, char *argv[], char *Optarg, int Optind)
1638 char tar_clipfl='\0';
1640 /* Reset back to defaults - could be from interactive version
1641 * reset mode and archive mode left as they are though
1653 if (tar_type=='c') {
1654 printf("Tar must be followed by only one of c or x.\n");
1660 if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1661 DEBUG(0,("Option b must be followed by valid blocksize\n"));
1672 DEBUG(0,("Option N must be followed by valid file name\n"));
1675 SMB_STRUCT_STAT stbuf;
1676 extern time_t newer_than;
1678 if (dos_stat(argv[Optind], &stbuf) == 0) {
1679 newer_than = stbuf.st_mtime;
1680 DEBUG(1,("Getting files newer than %s",
1681 asctime(LocalTime(&newer_than))));
1684 DEBUG(0,("Error setting newer-than time\n"));
1697 DEBUG(0,("Only one of I,X,F must be specified\n"));
1704 DEBUG(0,("Only one of I,X,F must be specified\n"));
1711 DEBUG(0,("Only one of I,X,F must be specified\n"));
1717 DEBUG(0, ("tar_re_search set\n"));
1718 tar_re_search = True;
1721 if (tar_type == 'c') {
1722 DEBUG(0, ("dry_run set\n"));
1725 DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1730 DEBUG(0,("Unknown tar option\n"));
1735 printf("Option T must be followed by one of c or x.\n");
1739 /* tar_excl is true if cliplist lists files to be included.
1740 * Both 'I' and 'F' mean include. */
1741 tar_excl=tar_clipfl!='X';
1743 if (tar_clipfl=='F') {
1744 if (argc-Optind-1 != 1) {
1745 DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1748 if (! read_inclusion_file(argv[Optind+1])) {
1751 } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
1756 cliplist=argv+Optind+1;
1757 clipn=argc-Optind-1;
1760 if ((tmplist=malloc(clipn*sizeof(char *))) == NULL) {
1761 DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n",
1767 for (clipcount = 0; clipcount < clipn; clipcount++) {
1769 DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1771 if ((tmpstr = (char *)malloc(strlen(cliplist[clipcount])+1)) == NULL) {
1772 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n",
1777 unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
1778 tmplist[clipcount] = tmpstr;
1779 DEBUG(5, ("Processed an item, %s\n", tmpstr));
1781 DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1784 must_free_cliplist = True;
1787 if (Optind+1<argc && tar_re_search) { /* Doing regular expression seaches */
1791 if ((preg = (regex_t *)malloc(65536)) == NULL) {
1793 DEBUG(0, ("Could not allocate buffer for regular expression search\n"));
1798 if (errcode = regcomp(preg, argv[Optind + 1], REG_EXTENDED)) {
1802 errlen = regerror(errcode, preg, errstr, sizeof(errstr) - 1);
1804 DEBUG(0, ("Could not compile pattern buffer for re search: %s\n%s\n", argv[Optind + 1], errstr));
1810 clipn=argc-Optind-1;
1811 cliplist=argv+Optind+1;
1815 if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1816 /* Sets tar handle to either 0 or 1, as appropriate */
1817 tarhandle=(tar_type=='c');
1819 if (tar_type=='c' && (dry_run || strcmp(argv[Optind], "/dev/null")==0))
1822 DEBUG(0,("Output is /dev/null, assuming dry_run"));
1827 if ((tar_type=='x' && (tarhandle = open(argv[Optind], O_RDONLY)) == -1)
1828 || (tar_type=='c' && (tarhandle=creat(argv[Optind], 0644)) < 0))
1830 DEBUG(0,("Error opening local file %s - %s\n",
1831 argv[Optind], strerror(errno)));