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;
76 /* These defines are for the do_setrattr routine, to indicate
77 * setting and reseting of file attributes in the function call */
81 static uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
83 #ifndef CLIENT_TIMEOUT
84 #define CLIENT_TIMEOUT (30*1000)
87 static char *tarbuf, *buffer_p;
88 static int tp, ntarf, tbufsiz, ttarf;
89 /* Incremental mode */
91 /* Reset archive bit */
93 /* Include / exclude mode (true=include, false=exclude) */
95 /* use regular expressions for search on file names */
96 BOOL tar_re_search=False;
100 /* Do not dump anything, just calculate sizes */
102 /* Dump files with System attribute */
103 BOOL tar_system=True;
104 /* Dump files with Hidden attribute */
105 BOOL tar_hidden=True;
106 /* Be noisy - make a catalogue */
108 BOOL tar_real_noisy=False; /* Don't want to be really noisy by default */
111 static char **cliplist=NULL;
113 static BOOL must_free_cliplist = False;
115 extern file_info def_finfo;
116 extern BOOL lowercase;
118 extern BOOL readbraw_supported;
120 extern pstring cur_dir;
121 extern int get_total_time_ms;
122 extern int get_total_size;
128 static void writetarheader(int f, char *aname, int size, time_t mtime,
129 char *amode, unsigned char ftype);
130 static void do_atar(char *rname,char *lname,file_info *finfo1);
131 static void do_tar(file_info *finfo);
132 static void oct_it(long value, int ndgs, char *p);
133 static void fixtarname(char *tptr, char *fp, int l);
134 static int dotarbuf(int f, char *b, int n);
135 static void dozerobuf(int f, int n);
136 static void dotareof(int f);
137 static void initarbuf(void);
139 /* restore functions */
140 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix);
141 static long unoct(char *p, int ndgs);
142 static void do_tarput(void);
143 static void unfixtarname(char *tptr, char *fp, int l, BOOL first);
146 * tar specific utitlities
149 /*******************************************************************
150 Create a string of size size+1 (for the null)
151 *******************************************************************/
152 static char *string_create_s(int size)
156 tmp = (char *)malloc(size+1);
160 DEBUG(0, ("Out of memory in string_create_s\n"));
168 /****************************************************************************
169 Write a tar header to buffer
170 ****************************************************************************/
171 static void writetarheader(int f, char *aname, int size, time_t mtime,
172 char *amode, unsigned char ftype)
178 DEBUG(5, ("WriteTarHdr, Type = %c, Size= %i, Name = %s\n", ftype, size, aname));
180 memset(hb.dummy, 0, sizeof(hb.dummy));
184 /* write a GNU tar style long header */
186 b = (char *)malloc(l+TBLOCK+100);
188 DEBUG(0,("out of memory\n"));
191 writetarheader(f, "/./@LongLink", l+1, 0, " 0 \0", 'L');
192 memset(b, 0, l+TBLOCK+100);
193 fixtarname(b, aname, l);
195 DEBUG(5, ("File name in tar file: %s, size=%i, \n", b, strlen(b)));
196 dotarbuf(f, b, TBLOCK*(((i-1)/TBLOCK)+1));
200 /* use l + 1 to do the null too */
201 fixtarname(hb.dbuf.name, aname, (l >= NAMSIZ) ? NAMSIZ : l + 1);
204 strlower(hb.dbuf.name);
206 /* write out a "standard" tar format header */
208 hb.dbuf.name[NAMSIZ-1]='\0';
209 safe_strcpy(hb.dbuf.mode, amode, strlen(amode));
210 oct_it(0L, 8, hb.dbuf.uid);
211 oct_it(0L, 8, hb.dbuf.gid);
212 oct_it((long) size, 13, hb.dbuf.size);
213 oct_it((long) mtime, 13, hb.dbuf.mtime);
214 memcpy(hb.dbuf.chksum, " ", sizeof(hb.dbuf.chksum));
215 memset(hb.dbuf.linkname, 0, NAMSIZ);
216 hb.dbuf.linkflag=ftype;
218 for (chk=0, i=sizeof(hb.dummy), jp=hb.dummy; --i>=0;) chk+=(0xFF & *jp++);
220 oct_it((long) chk, 8, hb.dbuf.chksum);
221 hb.dbuf.chksum[6] = '\0';
223 (void) dotarbuf(f, hb.dummy, sizeof(hb.dummy));
226 /****************************************************************************
227 Read a tar header into a hblock structure, and validate
228 ***************************************************************************/
229 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix)
236 * read in a "standard" tar format header - we're not that interested
237 * in that many fields, though
240 /* check the checksum */
241 for (chk=0, i=sizeof(hb->dummy), jp=hb->dummy; --i>=0;) chk+=(0xFF & *jp++);
246 /* compensate for blanks in chksum header */
247 for (i=sizeof(hb->dbuf.chksum), jp=hb->dbuf.chksum; --i>=0;)
250 chk += ' ' * sizeof(hb->dbuf.chksum);
252 fchk=unoct(hb->dbuf.chksum, sizeof(hb->dbuf.chksum));
254 DEBUG(5, ("checksum totals chk=%ld fchk=%ld chksum=%s\n",
255 chk, fchk, hb->dbuf.chksum));
259 DEBUG(0, ("checksums don't match %ld %ld\n", fchk, chk));
260 dump_data(5, (char *)hb - TBLOCK, TBLOCK *3);
264 if ((finfo->name = string_create_s(strlen(prefix) + strlen(hb -> dbuf.name) + 3)) == NULL) {
266 DEBUG(0, ("Out of space creating file_info2 for %s\n", hb -> dbuf.name));
271 safe_strcpy(finfo->name, prefix, strlen(prefix) + strlen(hb -> dbuf.name) + 3);
273 /* use l + 1 to do the null too; do prefix - prefcnt to zap leading slash */
274 unfixtarname(finfo->name + strlen(prefix), hb->dbuf.name,
275 strlen(hb->dbuf.name) + 1, True);
277 /* can't handle some links at present */
278 if ((hb->dbuf.linkflag != '0') && (hb -> dbuf.linkflag != '5')) {
279 if (hb->dbuf.linkflag == 0) {
280 DEBUG(6, ("Warning: NULL link flag (gnu tar archive ?) %s\n",
283 if (hb -> dbuf.linkflag == 'L') { /* We have a longlink */
284 /* Do nothing here at the moment. do_tarput will handle this
285 as long as the longlink gets back to it, as it has to advance
286 the buffer pointer, etc */
289 DEBUG(0, ("this tar file appears to contain some kind of link other than a GNUtar Longlink - ignoring\n"));
295 if ((unoct(hb->dbuf.mode, sizeof(hb->dbuf.mode)) & S_IFDIR)
296 || (*(finfo->name+strlen(finfo->name)-1) == '\\'))
301 finfo->mode=0; /* we don't care about mode at the moment, we'll
302 * just make it a regular file */
304 * Bug fix by richard@sj.co.uk
306 * REC: restore times correctly (as does tar)
307 * We only get the modification time of the file; set the creation time
308 * from the mod. time, and the access time to current time
310 finfo->mtime = finfo->ctime = strtol(hb->dbuf.mtime, NULL, 8);
311 finfo->atime = time(NULL);
312 finfo->size = unoct(hb->dbuf.size, sizeof(hb->dbuf.size));
317 /****************************************************************************
318 Write out the tar buffer to tape or wherever
319 ****************************************************************************/
320 static int dotarbuf(int f, char *b, int n)
327 /* This routine and the next one should be the only ones that do write()s */
328 if (tp + n >= tbufsiz)
333 memcpy(tarbuf + tp, b, diff);
334 fail=fail && (1+write(f, tarbuf, tbufsiz));
341 fail=fail && (1 + write(f, b, tbufsiz));
347 memcpy(tarbuf+tp, b, n);
351 return(fail ? writ : 0);
354 /****************************************************************************
355 Write zeros to buffer / tape
356 ****************************************************************************/
357 static void dozerobuf(int f, int n)
359 /* short routine just to write out n zeros to buffer -
360 * used to round files to nearest block
361 * and to do tar EOFs */
368 memset(tarbuf+tp, 0, tbufsiz-tp);
370 write(f, tarbuf, tbufsiz);
371 memset(tarbuf, 0, (tp+=n-tbufsiz));
375 memset(tarbuf+tp, 0, n);
380 /****************************************************************************
382 ****************************************************************************/
383 static void initarbuf(void)
385 /* initialize tar buffer */
386 tbufsiz=blocksize*TBLOCK;
387 tarbuf=malloc(tbufsiz); /* FIXME: We might not get the buffer */
389 /* reset tar buffer pointer and tar file counter and total dumped */
390 tp=0; ntarf=0; ttarf=0;
393 /****************************************************************************
394 Write two zero blocks at end of file
395 ****************************************************************************/
396 static void dotareof(int f)
398 SMB_STRUCT_STAT stbuf;
399 /* Two zero blocks at end of file, write out full buffer */
404 (void) dozerobuf(f, TBLOCK);
405 (void) dozerobuf(f, TBLOCK);
407 if (sys_fstat(f, &stbuf) == -1)
409 DEBUG(0, ("Couldn't stat file handle\n"));
413 /* Could be a pipe, in which case S_ISREG should fail,
414 * and we should write out at full size */
415 if (tp > 0) write(f, tarbuf, S_ISREG(stbuf.st_mode) ? tp : tbufsiz);
418 /****************************************************************************
419 (Un)mangle DOS pathname, make nonabsolute
420 ****************************************************************************/
421 static void fixtarname(char *tptr, char *fp, int l)
423 /* add a '.' to start of file name, convert from ugly dos \'s in path
424 * to lovely unix /'s :-} */
430 if((skip = skip_multibyte_char( *fp)) != 0) {
435 } else if (skip == 1) {
439 } else if (*fp == '\\') {
450 /****************************************************************************
451 Convert from decimal to octal string
452 ****************************************************************************/
453 static void oct_it (long value, int ndgs, char *p)
455 /* Converts long to octal string, pads with leading zeros */
457 /* skip final null, but do final space */
461 /* Loop does at least one digit */
463 p[--ndgs] = '0' + (char) (value & 7);
466 while (ndgs > 0 && value != 0);
468 /* Do leading zeros */
473 /****************************************************************************
474 Convert from octal string to long
475 ***************************************************************************/
476 static long unoct(char *p, int ndgs)
479 /* Converts octal string to long, ignoring any non-digit */
483 if (isdigit((int)*p))
484 value = (value << 3) | (long) (*p - '0');
492 /****************************************************************************
493 Compare two strings in a slash insensitive way, allowing s1 to match s2
494 if s1 is an "initial" string (up to directory marker). Thus, if s2 is
495 a file in any subdirectory of s1, declare a match.
496 ***************************************************************************/
497 static int strslashcmp(char *s1, char *s2)
503 || tolower(*s1) == tolower(*s2)
504 || (*s1 == '\\' && *s2=='/')
505 || (*s1 == '/' && *s2=='\\'))) {
509 /* if s1 has a trailing slash, it compared equal, so s1 is an "initial"
512 if (!*s1 && s1 != s1_0 && (*(s1-1) == '/' || *(s1-1) == '\\')) return 0;
514 /* ignore trailing slash on s1 */
515 if (!*s2 && (*s1 == '/' || *s1 == '\\') && !*(s1+1)) return 0;
517 /* check for s1 is an "initial" string of s2 */
518 if (*s2 == '/' || *s2 == '\\') return 0;
524 /****************************************************************************
525 Ensure a remote path exists (make if necessary)
526 ***************************************************************************/
527 static BOOL ensurepath(char *fname)
529 /* *must* be called with buffer ready malloc'ed */
530 /* ensures path exists */
532 char *partpath, *ffname;
533 char *p=fname, *basehack;
535 DEBUG(5, ( "Ensurepath called with: %s\n", fname));
537 partpath = string_create_s(strlen(fname));
538 ffname = string_create_s(strlen(fname));
540 if ((partpath == NULL) || (ffname == NULL)){
542 DEBUG(0, ("Out of memory in ensurepath: %s\n", fname));
549 /* fname copied to ffname so can strtok */
551 safe_strcpy(ffname, fname, strlen(fname));
553 /* do a `basename' on ffname, so don't try and make file name directory */
554 if ((basehack=strrchr(ffname, '\\')) == NULL)
559 p=strtok(ffname, "\\");
563 safe_strcat(partpath, p, strlen(fname) + 1);
565 if (!cli_chkpath(cli, partpath)) {
566 if (!cli_mkdir(cli, partpath))
568 DEBUG(0, ("Error mkdirhiering\n"));
572 DEBUG(3, ("mkdirhiering %s\n", partpath));
576 safe_strcat(partpath, "\\", strlen(fname) + 1);
577 p = strtok(NULL,"/\\");
583 static int padit(char *buf, int bufsize, int padsize)
588 DEBUG(5, ("Padding with %d zeros\n", padsize));
589 memset(buf, 0, bufsize);
590 while( !berr && padsize > 0 ) {
591 bytestowrite= MIN(bufsize, padsize);
592 berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite;
593 padsize -= bytestowrite;
600 static void do_setrattr(char *name, uint16 attr, int set)
604 if (!cli_getatr(cli, name, &oldattr, NULL, NULL)) return;
606 if (set == ATTRSET) {
609 attr = oldattr & ~attr;
612 if (!cli_setatr(cli, name, attr, 0)) {
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 DEBUG(5, ("Doing list with mtar_mask: %s\n", mtar_mask));
853 do_list(mtar_mask, attribute, do_tar, False, True);
854 safe_strcpy(cur_dir,saved_curdir, sizeof(pstring));
858 safe_strcpy(rname,cur_dir, sizeof(pstring));
859 safe_strcat(rname,finfo->name, sizeof(pstring));
860 do_atar(rname,finfo->name,finfo);
864 /****************************************************************************
865 Convert from UNIX to DOS file names
866 ***************************************************************************/
867 static void unfixtarname(char *tptr, char *fp, int l, BOOL first)
869 /* remove '.' from start of file name, convert from unix /'s to
870 * dos \'s in path. Kill any absolute path names. But only if first!
873 DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
880 if (*fp == '\\' || *fp == '/') {
888 if(( skip = skip_multibyte_char( *fp )) != 0) {
893 } else if (skip == 1) {
897 } else if (*fp == '/') {
909 /****************************************************************************
910 Move to the next block in the buffer, which may mean read in another set of
911 blocks. FIXME, we should allow more than one block to be skipped.
912 ****************************************************************************/
913 static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
915 int bufread, total = 0;
917 DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp));
921 if (*bufferp >= (ltarbuf + bufsiz)) {
923 DEBUG(5, ("Reading more data into ltarbuf ...\n"));
927 for (bufread = read(tarhandle, ltarbuf, bufsiz); total < bufsiz; total += bufread) {
929 if (bufread <= 0) { /* An error, return false */
930 return (total > 0 ? -2 : bufread);
935 DEBUG(5, ("Total bytes read ... %i\n", total));
945 /* Skip a file, even if it includes a long file name? */
946 static int skip_file(int skipsize)
948 int dsize = skipsize;
950 DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
952 /* FIXME, we should skip more than one block at a time */
956 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
958 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
970 /* We get a file from the tar file and store it */
971 static int get_file(file_info2 finfo)
973 int fsize = finfo.size;
974 int fnum = -1, pos = 0, dsize = 0, rsize = 0, bpos = 0;
976 DEBUG(5, ("get_file: file: %s, size %i\n", finfo.name, fsize));
978 if (ensurepath(finfo.name) &&
979 (fnum=cli_open(cli, finfo.name, O_WRONLY|O_CREAT|O_TRUNC, DENY_NONE)) == -1)
981 DEBUG(0, ("abandoning restore\n"));
985 /* read the blocks from the tar file and write to the remote file */
987 rsize = fsize; /* This is how much to write */
991 /* We can only write up to the end of the buffer */
993 dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, 65520); /* Calculate the size to write */
994 dsize = MIN(dsize, rsize); /* Should be only what is left */
995 DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos));
997 if (cli_write(cli, fnum, 0, buffer_p + bpos, pos, dsize) != dsize) {
998 DEBUG(0, ("Error writing remote file\n"));
1005 /* Now figure out how much to move in the buffer */
1007 /* FIXME, we should skip more than one block at a time */
1009 /* First, skip any initial part of the part written that is left over */
1010 /* from the end of the first TBLOCK */
1012 if ((bpos) && ((bpos + dsize) >= TBLOCK)) {
1014 dsize -= (TBLOCK - bpos); /* Get rid of the end of the first block */
1017 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) { /* and skip the block */
1018 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1025 while (dsize >= TBLOCK) {
1027 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1029 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1042 /* Now close the file ... */
1044 if (!cli_close(cli, fnum)) {
1045 DEBUG(0, ("Error closing remote file\n"));
1049 /* Now we update the creation date ... */
1051 DEBUG(5, ("Updating creation date on %s\n", finfo.name));
1053 if (!cli_setatr(cli, finfo.name, finfo.mode, finfo.mtime)) {
1054 if (tar_real_noisy) {
1055 DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
1056 /*return(False); */ /* Ignore, as Win95 does not allow changes */
1062 DEBUG(0, ("restore tar file %s of size %d bytes\n", finfo.name, finfo.size));
1067 /* Create a directory. We just ensure that the path exists and return as there
1068 is no file associated with a directory
1070 static int get_dir(file_info2 finfo)
1073 DEBUG(5, ("Creating directory: %s\n", finfo.name));
1075 if (!ensurepath(finfo.name)) {
1077 DEBUG(0, ("Problems creating directory\n"));
1084 /* Get a file with a long file name ... first file has file name, next file
1085 has the data. We only want the long file name, as the loop in do_tarput
1086 will deal with the rest.
1088 static char * get_longfilename(file_info2 finfo)
1090 int namesize = finfo.size + strlen(cur_dir) + 2;
1091 char *longname = malloc(namesize);
1092 int offset = 0, left = finfo.size;
1095 DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
1096 DEBUG(5, ("Len = %i\n", finfo.size));
1098 if (longname == NULL) {
1100 DEBUG(0, ("could not allocate buffer of size %d for longname\n",
1101 finfo.size + strlen(cur_dir) + 2));
1105 /* First, add cur_dir to the long file name */
1107 if (strlen(cur_dir) > 0) {
1108 strncpy(longname, cur_dir, namesize);
1109 offset = strlen(cur_dir);
1112 /* Loop through the blocks picking up the name */
1116 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1118 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1123 unfixtarname(longname + offset, buffer_p, MIN(TBLOCK, finfo.size), first--);
1124 DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
1135 static void do_tarput(void)
1138 struct timeval tp_start;
1139 char *longfilename = NULL, linkflag;
1142 GetTimeOfDay(&tp_start);
1144 DEBUG(5, ("RJS do_tarput called ...\n"));
1146 buffer_p = tarbuf + tbufsiz; /* init this to force first read */
1148 /* Now read through those files ... */
1152 /* Get us to the next block, or the first block first time around */
1154 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1156 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1162 DEBUG(5, ("Reading the next header ...\n"));
1164 switch (readtarheader((union hblock *) buffer_p, &finfo, cur_dir)) {
1166 case -2: /* Hmm, not good, but not fatal */
1167 DEBUG(0, ("Skipping %s...\n", finfo.name));
1168 if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) &&
1169 !skip_file(finfo.size)) {
1171 DEBUG(0, ("Short file, bailing out...\n"));
1179 DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
1182 case 0: /* chksum is zero - looks like an EOF */
1183 DEBUG(0, ("total of %d tar files restored to share\n", ntarf));
1184 return; /* Hmmm, bad here ... */
1193 /* Now, do we have a long file name? */
1195 if (longfilename != NULL) {
1197 free(finfo.name); /* Free the space already allocated */
1198 finfo.name = longfilename;
1199 longfilename = NULL;
1203 /* Well, now we have a header, process the file ... */
1205 /* Should we skip the file? We have the long name as well here */
1208 ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl)
1210 || (tar_re_search && !regexec(preg, finfo.name, 0, NULL, 0)));
1212 || (tar_re_search && mask_match(finfo.name, cliplist[0], True, False)));
1215 DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
1219 skip_file(finfo.size);
1224 /* We only get this far if we should process the file */
1225 linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
1229 case '0': /* Should use symbolic names--FIXME */
1231 /* Skip to the next block first, so we can get the file, FIXME, should
1232 be in get_file ... */
1234 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1235 DEBUG(0, ("Short file, bailing out...\n"));
1238 if (!get_file(finfo)) {
1239 DEBUG(0, ("Abandoning restore\n"));
1246 if (!get_dir(finfo)) {
1247 DEBUG(0, ("Abandoning restore \n"));
1253 longfilename = get_longfilename(finfo);
1254 if (!longfilename) {
1255 DEBUG(0, ("abandoning restore\n"));
1259 DEBUG(5, ("Long file name: %s\n", longfilename));
1263 skip_file(finfo.size); /* Don't handle these yet */
1275 * samba interactive commands
1278 /****************************************************************************
1280 ***************************************************************************/
1281 void cmd_block(void)
1286 if (!next_token(NULL,buf,NULL,sizeof(buf)))
1288 DEBUG(0, ("blocksize <n>\n"));
1293 if (block < 0 || block > 65535)
1295 DEBUG(0, ("blocksize out of range"));
1300 DEBUG(2,("blocksize is now %d\n", blocksize));
1303 /****************************************************************************
1304 command to set incremental / reset mode
1305 ***************************************************************************/
1306 void cmd_tarmode(void)
1310 while (next_token(NULL,buf,NULL,sizeof(buf))) {
1311 if (strequal(buf, "full"))
1313 else if (strequal(buf, "inc"))
1315 else if (strequal(buf, "reset"))
1317 else if (strequal(buf, "noreset"))
1319 else if (strequal(buf, "system"))
1321 else if (strequal(buf, "nosystem"))
1323 else if (strequal(buf, "hidden"))
1325 else if (strequal(buf, "nohidden"))
1327 else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
1329 else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
1331 else DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
1334 DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
1335 tar_inc ? "incremental" : "full",
1336 tar_system ? "system" : "nosystem",
1337 tar_hidden ? "hidden" : "nohidden",
1338 tar_reset ? "reset" : "noreset",
1339 tar_noisy ? "verbose" : "quiet"));
1343 /****************************************************************************
1344 Feeble attrib command
1345 ***************************************************************************/
1346 void cmd_setmode(void)
1354 attra[0] = attra[1] = 0;
1356 if (!next_token(NULL,buf,NULL,sizeof(buf)))
1358 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1362 safe_strcpy(fname, cur_dir, sizeof(pstring));
1363 safe_strcat(fname, buf, sizeof(pstring));
1365 while (next_token(NULL,buf,NULL,sizeof(buf))) {
1374 case 'r': attra[direct]|=aRONLY;
1376 case 'h': attra[direct]|=aHIDDEN;
1378 case 's': attra[direct]|=aSYSTEM;
1380 case 'a': attra[direct]|=aARCH;
1382 default: DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1387 if (attra[ATTRSET]==0 && attra[ATTRRESET]==0)
1389 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1393 DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1394 do_setrattr(fname, attra[ATTRSET], ATTRSET);
1395 do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
1398 /****************************************************************************
1399 Principal command for creating / extracting
1400 ***************************************************************************/
1407 if (!next_token(NULL,buf,NULL,sizeof(buf)))
1409 DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
1413 argl=toktocliplist(&argcl, NULL);
1414 if (!tar_parseargs(argcl, argl, buf, 0))
1422 /****************************************************************************
1423 Command line (option) version
1424 ***************************************************************************/
1425 int process_tar(void)
1441 if (clipn && tar_excl) {
1445 for (i=0; i<clipn; i++) {
1446 DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
1448 if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1449 *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1452 if (strrchr(cliplist[i], '\\')) {
1455 safe_strcpy(saved_dir, cur_dir, sizeof(pstring));
1457 if (*cliplist[i]=='\\') {
1458 safe_strcpy(tarmac, cliplist[i], sizeof(pstring));
1460 safe_strcpy(tarmac, cur_dir, sizeof(pstring));
1461 safe_strcat(tarmac, cliplist[i], sizeof(pstring));
1463 safe_strcpy(cur_dir, tarmac, sizeof(pstring));
1464 *(strrchr(cur_dir, '\\')+1)='\0';
1466 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1467 do_list(tarmac,attribute,do_tar, False, True);
1468 safe_strcpy(cur_dir,saved_dir, sizeof(pstring));
1470 safe_strcpy(tarmac, cur_dir, sizeof(pstring));
1471 safe_strcat(tarmac, cliplist[i], sizeof(pstring));
1472 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1473 do_list(tarmac,attribute,do_tar, False, True);
1478 safe_strcpy(mask,cur_dir, sizeof(pstring));
1479 DEBUG(5, ("process_tar, do_list with mask: $s\n", mask));
1480 safe_strcat(mask,"\\*", sizeof(pstring));
1481 do_list(mask,attribute,do_tar,False, True);
1484 if (ntarf) dotareof(tarhandle);
1488 DEBUG(0, ("tar: dumped %d tar files\n", ntarf));
1489 DEBUG(0, ("Total bytes written: %d\n", ttarf));
1493 if (must_free_cliplist) {
1495 for (i = 0; i < clipn; ++i) {
1501 must_free_cliplist = False;
1507 /****************************************************************************
1508 Find a token (filename) in a clip list
1509 ***************************************************************************/
1510 static int clipfind(char **aret, int ret, char *tok)
1512 if (aret==NULL) return 0;
1514 /* ignore leading slashes or dots in token */
1515 while(strchr("/\\.", *tok)) tok++;
1520 /* ignore leading slashes or dots in list */
1521 while(strchr("/\\.", *pkey)) pkey++;
1523 if (!strslashcmp(pkey, tok)) return 1;
1529 /****************************************************************************
1530 Read list of files to include from the file and initialize cliplist
1532 ***************************************************************************/
1533 static int read_inclusion_file(char *filename)
1535 FILE *inclusion = NULL;
1536 char buf[MAXPATHLEN + 1];
1537 char *inclusion_buffer = NULL;
1538 int inclusion_buffer_size = 0;
1539 int inclusion_buffer_sofar = 0;
1546 buf[MAXPATHLEN] = '\0'; /* guarantee null-termination */
1547 if ((inclusion = sys_fopen(filename, "r")) == NULL) {
1548 /* XXX It would be better to include a reason for failure, but without
1549 * autoconf, it's hard to use strerror, sys_errlist, etc.
1551 DEBUG(0,("Unable to open inclusion file %s\n", filename));
1555 while ((! error) && (fgets(buf, sizeof(buf)-1, inclusion))) {
1556 if (inclusion_buffer == NULL) {
1557 inclusion_buffer_size = 1024;
1558 if ((inclusion_buffer = malloc(inclusion_buffer_size)) == NULL) {
1559 DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1565 if (buf[strlen(buf)-1] == '\n') {
1566 buf[strlen(buf)-1] = '\0';
1569 if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1570 inclusion_buffer_size *= 2;
1571 inclusion_buffer = Realloc(inclusion_buffer,inclusion_buffer_size);
1572 if (! inclusion_buffer) {
1573 DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1574 inclusion_buffer_size));
1580 safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
1581 inclusion_buffer_sofar += strlen(buf) + 1;
1587 /* Allocate an array of clipn + 1 char*'s for cliplist */
1588 cliplist = malloc((clipn + 1) * sizeof(char *));
1589 if (cliplist == NULL) {
1590 DEBUG(0,("failure allocating memory for cliplist\n"));
1593 cliplist[clipn] = NULL;
1594 p = inclusion_buffer;
1595 for (i = 0; (! error) && (i < clipn); i++) {
1596 /* set current item to NULL so array will be null-terminated even if
1597 * malloc fails below. */
1599 if ((tmpstr = (char *)malloc(strlen(p)+1)) == NULL) {
1600 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
1603 unfixtarname(tmpstr, p, strlen(p) + 1, True);
1604 cliplist[i] = tmpstr;
1605 if ((p = strchr(p, '\000')) == NULL) {
1606 DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1612 must_free_cliplist = True;
1616 if (inclusion_buffer) {
1617 free(inclusion_buffer);
1622 /* We know cliplist is always null-terminated */
1623 for (pp = cliplist; *pp; ++pp) {
1628 must_free_cliplist = False;
1633 /* cliplist and its elements are freed at the end of process_tar. */
1637 /****************************************************************************
1638 Parse tar arguments. Sets tar_type, tar_excl, etc.
1639 ***************************************************************************/
1640 int tar_parseargs(int argc, char *argv[], char *Optarg, int Optind)
1642 char tar_clipfl='\0';
1644 /* Reset back to defaults - could be from interactive version
1645 * reset mode and archive mode left as they are though
1657 if (tar_type=='c') {
1658 printf("Tar must be followed by only one of c or x.\n");
1664 if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1665 DEBUG(0,("Option b must be followed by valid blocksize\n"));
1676 DEBUG(0,("Option N must be followed by valid file name\n"));
1679 SMB_STRUCT_STAT stbuf;
1680 extern time_t newer_than;
1682 if (dos_stat(argv[Optind], &stbuf) == 0) {
1683 newer_than = stbuf.st_mtime;
1684 DEBUG(1,("Getting files newer than %s",
1685 asctime(LocalTime(&newer_than))));
1688 DEBUG(0,("Error setting newer-than time\n"));
1701 DEBUG(0,("Only one of I,X,F must be specified\n"));
1708 DEBUG(0,("Only one of I,X,F must be specified\n"));
1715 DEBUG(0,("Only one of I,X,F must be specified\n"));
1721 DEBUG(0, ("tar_re_search set\n"));
1722 tar_re_search = True;
1725 if (tar_type == 'c') {
1726 DEBUG(0, ("dry_run set\n"));
1729 DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1734 DEBUG(0,("Unknown tar option\n"));
1739 printf("Option T must be followed by one of c or x.\n");
1743 /* tar_excl is true if cliplist lists files to be included.
1744 * Both 'I' and 'F' mean include. */
1745 tar_excl=tar_clipfl!='X';
1747 if (tar_clipfl=='F') {
1748 if (argc-Optind-1 != 1) {
1749 DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1752 if (! read_inclusion_file(argv[Optind+1])) {
1755 } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
1760 cliplist=argv+Optind+1;
1761 clipn=argc-Optind-1;
1764 if ((tmplist=malloc(clipn*sizeof(char *))) == NULL) {
1765 DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n",
1771 for (clipcount = 0; clipcount < clipn; clipcount++) {
1773 DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1775 if ((tmpstr = (char *)malloc(strlen(cliplist[clipcount])+1)) == NULL) {
1776 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n",
1781 unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
1782 tmplist[clipcount] = tmpstr;
1783 DEBUG(5, ("Processed an item, %s\n", tmpstr));
1785 DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1788 must_free_cliplist = True;
1791 if (Optind+1<argc && tar_re_search) { /* Doing regular expression seaches */
1795 if ((preg = (regex_t *)malloc(65536)) == NULL) {
1797 DEBUG(0, ("Could not allocate buffer for regular expression search\n"));
1802 if (errcode = regcomp(preg, argv[Optind + 1], REG_EXTENDED)) {
1806 errlen = regerror(errcode, preg, errstr, sizeof(errstr) - 1);
1808 DEBUG(0, ("Could not compile pattern buffer for re search: %s\n%s\n", argv[Optind + 1], errstr));
1814 clipn=argc-Optind-1;
1815 cliplist=argv+Optind+1;
1819 if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1820 /* Sets tar handle to either 0 or 1, as appropriate */
1821 tarhandle=(tar_type=='c');
1823 * Make sure that dbf points to stderr if we are using stdout for
1829 if (tar_type=='c' && (dry_run || strcmp(argv[Optind], "/dev/null")==0))
1832 DEBUG(0,("Output is /dev/null, assuming dry_run"));
1837 if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1)
1838 || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0))
1840 DEBUG(0,("Error opening local file %s - %s\n",
1841 argv[Optind], strerror(errno)));