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 struct cli_state *cli;
74 /* These defines are for the do_setrattr routine, to indicate
75 * setting and reseting of file attributes in the function call */
79 static uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
81 #ifndef CLIENT_TIMEOUT
82 #define CLIENT_TIMEOUT (30*1000)
85 static char *tarbuf, *buffer_p;
86 static int tp, ntarf, tbufsiz;
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;
126 static void writetarheader(int f, char *aname, int size, time_t mtime,
127 char *amode, unsigned char ftype);
128 static void do_atar(char *rname,char *lname,file_info *finfo1);
129 static void do_tar(file_info *finfo);
130 static void oct_it(long value, int ndgs, char *p);
131 static void fixtarname(char *tptr, char *fp, int l);
132 static int dotarbuf(int f, char *b, int n);
133 static void dozerobuf(int f, int n);
134 static void dotareof(int f);
135 static void initarbuf(void);
137 /* restore functions */
138 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix);
139 static long unoct(char *p, int ndgs);
140 static void do_tarput(void);
141 static void unfixtarname(char *tptr, char *fp, int l, BOOL first);
144 * tar specific utitlities
147 /*******************************************************************
148 Create a string of size size+1 (for the null)
149 *******************************************************************/
150 static char *string_create_s(int size)
154 tmp = (char *)malloc(size+1);
158 DEBUG(0, ("Out of memory in string_create_s\n"));
166 /****************************************************************************
167 Write a tar header to buffer
168 ****************************************************************************/
169 static void writetarheader(int f, char *aname, int size, time_t mtime,
170 char *amode, unsigned char ftype)
176 DEBUG(5, ("WriteTarHdr, Type = %c, Size= %i, Name = %s\n", ftype, size, aname));
178 memset(hb.dummy, 0, sizeof(hb.dummy));
181 if (l >= NAMSIZ - 1) {
182 /* write a GNU tar style long header */
184 b = (char *)malloc(l+TBLOCK+100);
186 DEBUG(0,("out of memory\n"));
189 writetarheader(f, "/./@LongLink", l+2, 0, " 0 \0", 'L');
190 memset(b, 0, l+TBLOCK+100);
191 fixtarname(b, aname, l);
193 DEBUG(5, ("File name in tar file: %s, size=%d, \n", b, (int)strlen(b)));
194 dotarbuf(f, b, TBLOCK*(((i-1)/TBLOCK)+1));
198 /* use l + 1 to do the null too */
199 fixtarname(hb.dbuf.name, aname, (l >= NAMSIZ) ? NAMSIZ : l + 1);
202 strlower(hb.dbuf.name);
204 /* write out a "standard" tar format header */
206 hb.dbuf.name[NAMSIZ-1]='\0';
207 safe_strcpy(hb.dbuf.mode, amode, strlen(amode));
208 oct_it(0L, 8, hb.dbuf.uid);
209 oct_it(0L, 8, hb.dbuf.gid);
210 oct_it((long) size, 13, hb.dbuf.size);
211 oct_it((long) mtime, 13, hb.dbuf.mtime);
212 memcpy(hb.dbuf.chksum, " ", sizeof(hb.dbuf.chksum));
213 memset(hb.dbuf.linkname, 0, NAMSIZ);
214 hb.dbuf.linkflag=ftype;
216 for (chk=0, i=sizeof(hb.dummy), jp=hb.dummy; --i>=0;) chk+=(0xFF & *jp++);
218 oct_it((long) chk, 8, hb.dbuf.chksum);
219 hb.dbuf.chksum[6] = '\0';
221 (void) dotarbuf(f, hb.dummy, sizeof(hb.dummy));
224 /****************************************************************************
225 Read a tar header into a hblock structure, and validate
226 ***************************************************************************/
227 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix)
234 * read in a "standard" tar format header - we're not that interested
235 * in that many fields, though
238 /* check the checksum */
239 for (chk=0, i=sizeof(hb->dummy), jp=hb->dummy; --i>=0;) chk+=(0xFF & *jp++);
244 /* compensate for blanks in chksum header */
245 for (i=sizeof(hb->dbuf.chksum), jp=hb->dbuf.chksum; --i>=0;)
248 chk += ' ' * sizeof(hb->dbuf.chksum);
250 fchk=unoct(hb->dbuf.chksum, sizeof(hb->dbuf.chksum));
252 DEBUG(5, ("checksum totals chk=%ld fchk=%ld chksum=%s\n",
253 chk, fchk, hb->dbuf.chksum));
257 DEBUG(0, ("checksums don't match %ld %ld\n", fchk, chk));
258 dump_data(5, (char *)hb - TBLOCK, TBLOCK *3);
262 if ((finfo->name = string_create_s(strlen(prefix) + strlen(hb -> dbuf.name) + 3)) == NULL) {
264 DEBUG(0, ("Out of space creating file_info2 for %s\n", hb -> dbuf.name));
269 safe_strcpy(finfo->name, prefix, strlen(prefix) + strlen(hb -> dbuf.name) + 3);
271 /* use l + 1 to do the null too; do prefix - prefcnt to zap leading slash */
272 unfixtarname(finfo->name + strlen(prefix), hb->dbuf.name,
273 strlen(hb->dbuf.name) + 1, True);
275 /* can't handle some links at present */
276 if ((hb->dbuf.linkflag != '0') && (hb -> dbuf.linkflag != '5')) {
277 if (hb->dbuf.linkflag == 0) {
278 DEBUG(6, ("Warning: NULL link flag (gnu tar archive ?) %s\n",
281 if (hb -> dbuf.linkflag == 'L') { /* We have a longlink */
282 /* Do nothing here at the moment. do_tarput will handle this
283 as long as the longlink gets back to it, as it has to advance
284 the buffer pointer, etc */
287 DEBUG(0, ("this tar file appears to contain some kind of link other than a GNUtar Longlink - ignoring\n"));
293 if ((unoct(hb->dbuf.mode, sizeof(hb->dbuf.mode)) & S_IFDIR)
294 || (*(finfo->name+strlen(finfo->name)-1) == '\\'))
299 finfo->mode=0; /* we don't care about mode at the moment, we'll
300 * just make it a regular file */
302 * Bug fix by richard@sj.co.uk
304 * REC: restore times correctly (as does tar)
305 * We only get the modification time of the file; set the creation time
306 * from the mod. time, and the access time to current time
308 finfo->mtime = finfo->ctime = strtol(hb->dbuf.mtime, NULL, 8);
309 finfo->atime = time(NULL);
310 finfo->size = unoct(hb->dbuf.size, sizeof(hb->dbuf.size));
315 /****************************************************************************
316 Write out the tar buffer to tape or wherever
317 ****************************************************************************/
318 static int dotarbuf(int f, char *b, int n)
325 /* This routine and the next one should be the only ones that do write()s */
326 if (tp + n >= tbufsiz)
331 memcpy(tarbuf + tp, b, diff);
332 fail=fail && (1+write(f, tarbuf, tbufsiz));
339 fail=fail && (1 + write(f, b, tbufsiz));
345 memcpy(tarbuf+tp, b, n);
349 return(fail ? writ : 0);
352 /****************************************************************************
353 Write zeros to buffer / tape
354 ****************************************************************************/
355 static void dozerobuf(int f, int n)
357 /* short routine just to write out n zeros to buffer -
358 * used to round files to nearest block
359 * and to do tar EOFs */
366 memset(tarbuf+tp, 0, tbufsiz-tp);
368 write(f, tarbuf, tbufsiz);
369 memset(tarbuf, 0, (tp+=n-tbufsiz));
373 memset(tarbuf+tp, 0, n);
378 /****************************************************************************
380 ****************************************************************************/
381 static void initarbuf(void)
383 /* initialize tar buffer */
384 tbufsiz=blocksize*TBLOCK;
385 tarbuf=malloc(tbufsiz); /* FIXME: We might not get the buffer */
387 /* reset tar buffer pointer and tar file counter and total dumped */
388 tp=0; ntarf=0; ttarf=0;
391 /****************************************************************************
392 Write two zero blocks at end of file
393 ****************************************************************************/
394 static void dotareof(int f)
396 SMB_STRUCT_STAT stbuf;
397 /* Two zero blocks at end of file, write out full buffer */
402 (void) dozerobuf(f, TBLOCK);
403 (void) dozerobuf(f, TBLOCK);
405 if (sys_fstat(f, &stbuf) == -1)
407 DEBUG(0, ("Couldn't stat file handle\n"));
411 /* Could be a pipe, in which case S_ISREG should fail,
412 * and we should write out at full size */
413 if (tp > 0) write(f, tarbuf, S_ISREG(stbuf.st_mode) ? tp : tbufsiz);
416 /****************************************************************************
417 (Un)mangle DOS pathname, make nonabsolute
418 ****************************************************************************/
419 static void fixtarname(char *tptr, char *fp, int l)
421 /* add a '.' to start of file name, convert from ugly dos \'s in path
422 * to lovely unix /'s :-} */
425 safe_strcpy(tptr, fp, l);
426 string_replace(tptr, '\\', '/');
429 /****************************************************************************
430 Convert from decimal to octal string
431 ****************************************************************************/
432 static void oct_it (long value, int ndgs, char *p)
434 /* Converts long to octal string, pads with leading zeros */
436 /* skip final null, but do final space */
440 /* Loop does at least one digit */
442 p[--ndgs] = '0' + (char) (value & 7);
445 while (ndgs > 0 && value != 0);
447 /* Do leading zeros */
452 /****************************************************************************
453 Convert from octal string to long
454 ***************************************************************************/
455 static long unoct(char *p, int ndgs)
458 /* Converts octal string to long, ignoring any non-digit */
462 if (isdigit((int)*p))
463 value = (value << 3) | (long) (*p - '0');
471 /****************************************************************************
472 Compare two strings in a slash insensitive way, allowing s1 to match s2
473 if s1 is an "initial" string (up to directory marker). Thus, if s2 is
474 a file in any subdirectory of s1, declare a match.
475 ***************************************************************************/
476 static int strslashcmp(char *s1, char *s2)
482 || tolower(*s1) == tolower(*s2)
483 || (*s1 == '\\' && *s2=='/')
484 || (*s1 == '/' && *s2=='\\'))) {
488 /* if s1 has a trailing slash, it compared equal, so s1 is an "initial"
491 if (!*s1 && s1 != s1_0 && (*(s1-1) == '/' || *(s1-1) == '\\')) return 0;
493 /* ignore trailing slash on s1 */
494 if (!*s2 && (*s1 == '/' || *s1 == '\\') && !*(s1+1)) return 0;
496 /* check for s1 is an "initial" string of s2 */
497 if (*s2 == '/' || *s2 == '\\') return 0;
503 /****************************************************************************
504 Ensure a remote path exists (make if necessary)
505 ***************************************************************************/
506 static BOOL ensurepath(char *fname)
508 /* *must* be called with buffer ready malloc'ed */
509 /* ensures path exists */
511 char *partpath, *ffname;
512 char *p=fname, *basehack;
514 DEBUG(5, ( "Ensurepath called with: %s\n", fname));
516 partpath = string_create_s(strlen(fname));
517 ffname = string_create_s(strlen(fname));
519 if ((partpath == NULL) || (ffname == NULL)){
521 DEBUG(0, ("Out of memory in ensurepath: %s\n", fname));
528 /* fname copied to ffname so can strtok */
530 safe_strcpy(ffname, fname, strlen(fname));
532 /* do a `basename' on ffname, so don't try and make file name directory */
533 if ((basehack=strrchr_m(ffname, '\\')) == NULL)
538 p=strtok(ffname, "\\");
542 safe_strcat(partpath, p, strlen(fname) + 1);
544 if (!cli_chkpath(cli, partpath)) {
545 if (!cli_mkdir(cli, partpath))
547 DEBUG(0, ("Error mkdirhiering\n"));
551 DEBUG(3, ("mkdirhiering %s\n", partpath));
555 safe_strcat(partpath, "\\", strlen(fname) + 1);
556 p = strtok(NULL,"/\\");
562 static int padit(char *buf, int bufsize, int padsize)
567 DEBUG(5, ("Padding with %d zeros\n", padsize));
568 memset(buf, 0, bufsize);
569 while( !berr && padsize > 0 ) {
570 bytestowrite= MIN(bufsize, padsize);
571 berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite;
572 padsize -= bytestowrite;
579 static void do_setrattr(char *name, uint16 attr, int set)
583 if (!cli_getatr(cli, name, &oldattr, NULL, NULL)) return;
585 if (set == ATTRSET) {
588 attr = oldattr & ~attr;
591 if (!cli_setatr(cli, name, attr, 0)) {
592 DEBUG(1,("setatr failed: %s\n", cli_errstr(cli)));
597 /****************************************************************************
598 append one remote file to the tar file
599 ***************************************************************************/
600 static void do_atar(char *rname,char *lname,file_info *finfo1)
606 BOOL close_done = False;
607 BOOL shallitime=True;
609 int read_size = 65520;
612 struct timeval tp_start;
613 GetTimeOfDay(&tp_start);
615 ftype = '0'; /* An ordinary file ... */
618 finfo.size = finfo1 -> size;
619 finfo.mode = finfo1 -> mode;
620 finfo.uid = finfo1 -> uid;
621 finfo.gid = finfo1 -> gid;
622 finfo.mtime = finfo1 -> mtime;
623 finfo.atime = finfo1 -> atime;
624 finfo.ctime = finfo1 -> ctime;
627 finfo.size = def_finfo.size;
628 finfo.mode = def_finfo.mode;
629 finfo.uid = def_finfo.uid;
630 finfo.gid = def_finfo.gid;
631 finfo.mtime = def_finfo.mtime;
632 finfo.atime = def_finfo.atime;
633 finfo.ctime = def_finfo.ctime;
638 DEBUG(3,("skipping file %s of size %d bytes\n",
642 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
647 fnum = cli_open(cli, rname, O_RDONLY, DENY_NONE);
649 dos_clean_name(rname);
652 DEBUG(0,("%s opening remote file %s (%s)\n",
653 cli_errstr(cli),rname, cur_dir));
657 finfo.name = string_create_s(strlen(rname));
658 if (finfo.name == NULL) {
659 DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n"));
663 safe_strcpy(finfo.name,rname, strlen(rname));
665 if (!cli_getattrE(cli, fnum, &finfo.mode, &finfo.size, NULL, &finfo.atime, &finfo.mtime)) {
666 DEBUG(0, ("getattrE: %s\n", cli_errstr(cli)));
669 finfo.ctime = finfo.mtime;
672 DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
674 if (tar_inc && !(finfo.mode & aARCH))
676 DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
679 else if (!tar_system && (finfo.mode & aSYSTEM))
681 DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
684 else if (!tar_hidden && (finfo.mode & aHIDDEN))
686 DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
691 DEBUG(3,("getting file %s of size %d bytes as a tar file %s",
696 /* write a tar header, don't bother with mode - just set to 100644 */
697 writetarheader(tarhandle, rname, finfo.size, finfo.mtime, "100644 \0", ftype);
699 while (nread < finfo.size && !close_done) {
701 DEBUG(3,("nread=%d\n",nread));
703 datalen = cli_read(cli, fnum, data, nread, read_size);
706 DEBUG(0,("Error reading file %s : %s\n", rname, cli_errstr(cli)));
712 /* if file size has increased since we made file size query, truncate
713 read so tar header for this file will be correct.
716 if (nread > finfo.size) {
717 datalen -= nread - finfo.size;
718 DEBUG(0,("File size change - truncating %s to %d bytes\n", finfo.name, (int)finfo.size));
721 /* add received bits of file to buffer - dotarbuf will
722 * write out in 512 byte intervals */
723 if (dotarbuf(tarhandle,data,datalen) != datalen) {
724 DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
729 DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
736 /* pad tar file with zero's if we couldn't get entire file */
737 if (nread < finfo.size) {
738 DEBUG(0, ("Didn't get entire file. size=%d, nread=%d\n", (int)finfo.size, (int)nread));
739 if (padit(data, sizeof(data), finfo.size - nread))
740 DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
743 /* round tar file to nearest block */
744 if (finfo.size % TBLOCK)
745 dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
747 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
751 cli_close(cli, fnum);
755 struct timeval tp_end;
758 /* if shallitime is true then we didn't skip */
759 if (tar_reset && !dry_run)
760 (void) do_setrattr(finfo.name, aARCH, ATTRRESET);
762 GetTimeOfDay(&tp_end);
764 (tp_end.tv_sec - tp_start.tv_sec)*1000 +
765 (tp_end.tv_usec - tp_start.tv_usec)/1000;
766 get_total_time_ms += this_time;
767 get_total_size += finfo.size;
771 DEBUG(0, ("%10d (%7.1f kb/s) %s\n",
772 (int)finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
776 /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
777 DEBUG(3,("(%g kb/s) (average %g kb/s)\n",
778 finfo.size / MAX(0.001, (1.024*this_time)),
779 get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
783 /****************************************************************************
784 Append single file to tar file (or not)
785 ***************************************************************************/
786 static void do_tar(file_info *finfo)
790 if (strequal(finfo->name,"..") || strequal(finfo->name,"."))
793 /* Is it on the exclude list ? */
794 if (!tar_excl && clipn) {
797 DEBUG(5, ("Excl: strlen(cur_dir) = %d\n", (int)strlen(cur_dir)));
799 safe_strcpy(exclaim, cur_dir, sizeof(pstring));
800 *(exclaim+strlen(exclaim)-1)='\0';
802 safe_strcat(exclaim, "\\", sizeof(pstring));
803 safe_strcat(exclaim, finfo->name, sizeof(exclaim));
805 DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
807 if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
809 (tar_re_search && !regexec(preg, exclaim, 0, NULL, 0))) {
811 (tar_re_search && mask_match(exclaim, cliplist[0], True))) {
813 DEBUG(3,("Skipping file %s\n", exclaim));
818 if (finfo->mode & aDIR)
820 pstring saved_curdir;
823 safe_strcpy(saved_curdir, cur_dir, sizeof(saved_curdir));
825 DEBUG(5, ("Sizeof(cur_dir)=%d, strlen(cur_dir)=%d, strlen(finfo->name)=%d\nname=%s,cur_dir=%s\n", (int)sizeof(cur_dir), (int)strlen(cur_dir), (int)strlen(finfo->name), finfo->name, cur_dir));
827 safe_strcat(cur_dir,finfo->name, sizeof(cur_dir));
828 safe_strcat(cur_dir,"\\", sizeof(cur_dir));
830 DEBUG(5, ("Writing a dir, Name = %s\n", cur_dir));
832 /* write a tar directory, don't bother with mode - just set it to
834 writetarheader(tarhandle, cur_dir, 0, finfo->mtime, "040755 \0", '5');
836 DEBUG(0,(" directory %s\n", cur_dir));
838 ntarf++; /* Make sure we have a file on there */
839 safe_strcpy(mtar_mask,cur_dir, sizeof(pstring));
840 safe_strcat(mtar_mask,"*", sizeof(pstring));
841 DEBUG(5, ("Doing list with mtar_mask: %s\n", mtar_mask));
842 do_list(mtar_mask, attribute, do_tar, False, True);
843 safe_strcpy(cur_dir,saved_curdir, sizeof(pstring));
847 safe_strcpy(rname,cur_dir, sizeof(pstring));
848 safe_strcat(rname,finfo->name, sizeof(pstring));
849 do_atar(rname,finfo->name,finfo);
853 /****************************************************************************
854 Convert from UNIX to DOS file names
855 ***************************************************************************/
856 static void unfixtarname(char *tptr, char *fp, int l, BOOL first)
858 /* remove '.' from start of file name, convert from unix /'s to
859 * dos \'s in path. Kill any absolute path names. But only if first!
862 DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
869 if (*fp == '\\' || *fp == '/') {
875 safe_strcpy(tptr, fp, l);
876 string_replace(tptr, '/', '\\');
880 /****************************************************************************
881 Move to the next block in the buffer, which may mean read in another set of
882 blocks. FIXME, we should allow more than one block to be skipped.
883 ****************************************************************************/
884 static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
886 int bufread, total = 0;
888 DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp));
892 if (*bufferp >= (ltarbuf + bufsiz)) {
894 DEBUG(5, ("Reading more data into ltarbuf ...\n"));
897 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>
898 * Fixes bug where read can return short if coming from
902 bufread = read(tarhandle, ltarbuf, bufsiz);
905 while (total < bufsiz) {
906 if (bufread < 0) { /* An error, return false */
907 return (total > 0 ? -2 : bufread);
915 bufread = read(tarhandle, <arbuf[total], bufsiz - total);
919 DEBUG(5, ("Total bytes read ... %i\n", total));
929 /* Skip a file, even if it includes a long file name? */
930 static int skip_file(int skipsize)
932 int dsize = skipsize;
934 DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
936 /* FIXME, we should skip more than one block at a time */
940 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
942 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
954 /*************************************************************
955 Get a file from the tar file and store it.
956 When this is called, tarbuf already contains the first
957 file block. This is a bit broken & needs fixing.
958 **************************************************************/
960 static int get_file(file_info2 finfo)
962 int fnum = -1, pos = 0, dsize = 0, rsize = 0, bpos = 0;
964 DEBUG(5, ("get_file: file: %s, size %i\n", finfo.name, (int)finfo.size));
966 if (ensurepath(finfo.name) &&
967 (fnum=cli_open(cli, finfo.name, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE)) == -1) {
968 DEBUG(0, ("abandoning restore\n"));
972 /* read the blocks from the tar file and write to the remote file */
974 rsize = finfo.size; /* This is how much to write */
978 /* We can only write up to the end of the buffer */
980 dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, 65520); /* Calculate the size to write */
981 dsize = MIN(dsize, rsize); /* Should be only what is left */
982 DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos));
984 if (cli_write(cli, fnum, 0, buffer_p + bpos, pos, dsize) != dsize) {
985 DEBUG(0, ("Error writing remote file\n"));
992 /* Now figure out how much to move in the buffer */
994 /* FIXME, we should skip more than one block at a time */
996 /* First, skip any initial part of the part written that is left over */
997 /* from the end of the first TBLOCK */
999 if ((bpos) && ((bpos + dsize) >= TBLOCK)) {
1001 dsize -= (TBLOCK - bpos); /* Get rid of the end of the first block */
1004 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) { /* and skip the block */
1005 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1013 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>.
1014 * If the file being extracted is an exact multiple of
1015 * TBLOCK bytes then we don't want to extract the next
1016 * block from the tarfile here, as it will be done in
1017 * the caller of get_file().
1020 while (((rsize != 0) && (dsize >= TBLOCK)) ||
1021 ((rsize == 0) && (dsize > TBLOCK))) {
1023 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1024 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1035 /* Now close the file ... */
1037 if (!cli_close(cli, fnum)) {
1038 DEBUG(0, ("Error closing remote file\n"));
1042 /* Now we update the creation date ... */
1044 DEBUG(5, ("Updating creation date on %s\n", finfo.name));
1046 if (!cli_setatr(cli, finfo.name, finfo.mode, finfo.mtime)) {
1047 if (tar_real_noisy) {
1048 DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
1049 /*return(False); */ /* Ignore, as Win95 does not allow changes */
1055 DEBUG(0, ("restore tar file %s of size %d bytes\n", finfo.name, (int)finfo.size));
1060 /* Create a directory. We just ensure that the path exists and return as there
1061 is no file associated with a directory
1063 static int get_dir(file_info2 finfo)
1066 DEBUG(0, ("restore directory %s\n", finfo.name));
1068 if (!ensurepath(finfo.name)) {
1070 DEBUG(0, ("Problems creating directory\n"));
1079 /* Get a file with a long file name ... first file has file name, next file
1080 has the data. We only want the long file name, as the loop in do_tarput
1081 will deal with the rest.
1083 static char * get_longfilename(file_info2 finfo)
1085 int namesize = finfo.size + strlen(cur_dir) + 2;
1086 char *longname = malloc(namesize);
1087 int offset = 0, left = finfo.size;
1090 DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
1091 DEBUG(5, ("Len = %d\n", (int)finfo.size));
1093 if (longname == NULL) {
1095 DEBUG(0, ("could not allocate buffer of size %d for longname\n",
1096 (int)(finfo.size + strlen(cur_dir) + 2)));
1100 /* First, add cur_dir to the long file name */
1102 if (strlen(cur_dir) > 0) {
1103 strncpy(longname, cur_dir, namesize);
1104 offset = strlen(cur_dir);
1107 /* Loop through the blocks picking up the name */
1111 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1113 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1118 unfixtarname(longname + offset, buffer_p, MIN(TBLOCK, finfo.size), first--);
1119 DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
1130 static void do_tarput(void)
1133 struct timeval tp_start;
1134 char *longfilename = NULL, linkflag;
1137 GetTimeOfDay(&tp_start);
1139 DEBUG(5, ("RJS do_tarput called ...\n"));
1141 buffer_p = tarbuf + tbufsiz; /* init this to force first read */
1143 /* Now read through those files ... */
1147 /* Get us to the next block, or the first block first time around */
1149 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1151 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1157 DEBUG(5, ("Reading the next header ...\n"));
1159 switch (readtarheader((union hblock *) buffer_p, &finfo, cur_dir)) {
1161 case -2: /* Hmm, not good, but not fatal */
1162 DEBUG(0, ("Skipping %s...\n", finfo.name));
1163 if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) &&
1164 !skip_file(finfo.size)) {
1166 DEBUG(0, ("Short file, bailing out...\n"));
1174 DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
1177 case 0: /* chksum is zero - looks like an EOF */
1178 DEBUG(0, ("tar: restored %d files and directories\n", ntarf));
1179 return; /* Hmmm, bad here ... */
1188 /* Now, do we have a long file name? */
1190 if (longfilename != NULL) {
1192 SAFE_FREE(finfo.name); /* Free the space already allocated */
1193 finfo.name = longfilename;
1194 longfilename = NULL;
1198 /* Well, now we have a header, process the file ... */
1200 /* Should we skip the file? We have the long name as well here */
1203 ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl)
1205 || (tar_re_search && !regexec(preg, finfo.name, 0, NULL, 0)));
1207 || (tar_re_search && mask_match(finfo.name, cliplist[0], True)));
1210 DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
1214 skip_file(finfo.size);
1219 /* We only get this far if we should process the file */
1220 linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
1224 case '0': /* Should use symbolic names--FIXME */
1227 * Skip to the next block first, so we can get the file, FIXME, should
1228 * be in get_file ...
1229 * The 'finfo.size != 0' fix is from Bob Boehmer <boehmer@worldnet.att.net>
1230 * Fixes bug where file size in tarfile is zero.
1233 if ((finfo.size != 0) && 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_nr(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_nr(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_nr(NULL,buf,NULL,sizeof(buf)))
1357 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1361 safe_strcpy(fname, cur_dir, sizeof(pstring));
1362 safe_strcat(fname, buf, sizeof(pstring));
1364 while (next_token_nr(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> <[+|-]rsha>\n"));
1392 DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1393 do_setrattr(fname, attra[ATTRSET], ATTRSET);
1394 do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
1397 /****************************************************************************
1398 Principal command for creating / extracting
1399 ***************************************************************************/
1406 if (!next_token_nr(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_m(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_m(cur_dir, '\\')+1)='\0';
1465 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1466 do_list(tarmac,attribute,do_tar, False, True);
1467 safe_strcpy(cur_dir,saved_dir, sizeof(pstring));
1469 safe_strcpy(tarmac, cur_dir, sizeof(pstring));
1470 safe_strcat(tarmac, cliplist[i], sizeof(pstring));
1471 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1472 do_list(tarmac,attribute,do_tar, False, True);
1477 safe_strcpy(mask,cur_dir, sizeof(pstring));
1478 DEBUG(5, ("process_tar, do_list with mask: %s\n", mask));
1479 safe_strcat(mask,"\\*", sizeof(pstring));
1480 do_list(mask,attribute,do_tar,False, True);
1483 if (ntarf) dotareof(tarhandle);
1487 DEBUG(0, ("tar: dumped %d files and directories\n", ntarf));
1488 DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf));
1492 if (must_free_cliplist) {
1494 for (i = 0; i < clipn; ++i) {
1495 SAFE_FREE(cliplist[i]);
1497 SAFE_FREE(cliplist);
1500 must_free_cliplist = False;
1506 /****************************************************************************
1507 Find a token (filename) in a clip list
1508 ***************************************************************************/
1509 static int clipfind(char **aret, int ret, char *tok)
1511 if (aret==NULL) return 0;
1513 /* ignore leading slashes or dots in token */
1514 while(strchr_m("/\\.", *tok)) tok++;
1519 /* ignore leading slashes or dots in list */
1520 while(strchr_m("/\\.", *pkey)) pkey++;
1522 if (!strslashcmp(pkey, tok)) return 1;
1528 /****************************************************************************
1529 Read list of files to include from the file and initialize cliplist
1531 ***************************************************************************/
1532 static int read_inclusion_file(char *filename)
1534 XFILE *inclusion = NULL;
1535 char buf[MAXPATHLEN + 1];
1536 char *inclusion_buffer = NULL;
1537 int inclusion_buffer_size = 0;
1538 int inclusion_buffer_sofar = 0;
1545 buf[MAXPATHLEN] = '\0'; /* guarantee null-termination */
1546 if ((inclusion = x_fopen(filename, O_RDONLY, 0)) == NULL) {
1547 /* XXX It would be better to include a reason for failure, but without
1548 * autoconf, it's hard to use strerror, sys_errlist, etc.
1550 DEBUG(0,("Unable to open inclusion file %s\n", filename));
1554 while ((! error) && (x_fgets(buf, sizeof(buf)-1, inclusion))) {
1555 if (inclusion_buffer == NULL) {
1556 inclusion_buffer_size = 1024;
1557 if ((inclusion_buffer = malloc(inclusion_buffer_size)) == NULL) {
1558 DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1564 if (buf[strlen(buf)-1] == '\n') {
1565 buf[strlen(buf)-1] = '\0';
1568 if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1570 inclusion_buffer_size *= 2;
1571 ib = Realloc(inclusion_buffer,inclusion_buffer_size);
1573 DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1574 inclusion_buffer_size));
1578 else inclusion_buffer = ib;
1581 safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
1582 inclusion_buffer_sofar += strlen(buf) + 1;
1585 x_fclose(inclusion);
1588 /* Allocate an array of clipn + 1 char*'s for cliplist */
1589 cliplist = malloc((clipn + 1) * sizeof(char *));
1590 if (cliplist == NULL) {
1591 DEBUG(0,("failure allocating memory for cliplist\n"));
1594 cliplist[clipn] = NULL;
1595 p = inclusion_buffer;
1596 for (i = 0; (! error) && (i < clipn); i++) {
1597 /* set current item to NULL so array will be null-terminated even if
1598 * malloc fails below. */
1600 if ((tmpstr = (char *)malloc(strlen(p)+1)) == NULL) {
1601 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
1604 unfixtarname(tmpstr, p, strlen(p) + 1, True);
1605 cliplist[i] = tmpstr;
1606 if ((p = strchr_m(p, '\000')) == NULL) {
1607 DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1613 must_free_cliplist = True;
1617 SAFE_FREE(inclusion_buffer);
1621 /* We know cliplist is always null-terminated */
1622 for (pp = cliplist; *pp; ++pp) {
1625 SAFE_FREE(cliplist);
1627 must_free_cliplist = False;
1632 /* cliplist and its elements are freed at the end of process_tar. */
1636 /****************************************************************************
1637 Parse tar arguments. Sets tar_type, tar_excl, etc.
1638 ***************************************************************************/
1639 int tar_parseargs(int argc, char *argv[], char *Optarg, int Optind)
1641 char tar_clipfl='\0';
1643 /* Reset back to defaults - could be from interactive version
1644 * reset mode and archive mode left as they are though
1656 if (tar_type=='c') {
1657 printf("Tar must be followed by only one of c or x.\n");
1663 if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1664 DEBUG(0,("Option b must be followed by valid blocksize\n"));
1675 DEBUG(0,("Option N must be followed by valid file name\n"));
1678 SMB_STRUCT_STAT stbuf;
1679 extern time_t newer_than;
1681 if (sys_stat(argv[Optind], &stbuf) == 0) {
1682 newer_than = stbuf.st_mtime;
1683 DEBUG(1,("Getting files newer than %s",
1684 asctime(LocalTime(&newer_than))));
1687 DEBUG(0,("Error setting newer-than time\n"));
1700 DEBUG(0,("Only one of I,X,F must be specified\n"));
1707 DEBUG(0,("Only one of I,X,F must be specified\n"));
1714 DEBUG(0,("Only one of I,X,F must be specified\n"));
1720 DEBUG(0, ("tar_re_search set\n"));
1721 tar_re_search = True;
1724 if (tar_type == 'c') {
1725 DEBUG(0, ("dry_run set\n"));
1728 DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1733 DEBUG(0,("Unknown tar option\n"));
1738 printf("Option T must be followed by one of c or x.\n");
1742 /* tar_excl is true if cliplist lists files to be included.
1743 * Both 'I' and 'F' mean include. */
1744 tar_excl=tar_clipfl!='X';
1746 if (tar_clipfl=='F') {
1747 if (argc-Optind-1 != 1) {
1748 DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1751 if (! read_inclusion_file(argv[Optind+1])) {
1754 } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
1759 cliplist=argv+Optind+1;
1760 clipn=argc-Optind-1;
1763 if ((tmplist=malloc(clipn*sizeof(char *))) == NULL) {
1764 DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n",
1770 for (clipcount = 0; clipcount < clipn; clipcount++) {
1772 DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1774 if ((tmpstr = (char *)malloc(strlen(cliplist[clipcount])+1)) == NULL) {
1775 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n",
1780 unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
1781 tmplist[clipcount] = tmpstr;
1782 DEBUG(5, ("Processed an item, %s\n", tmpstr));
1784 DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1787 must_free_cliplist = True;
1790 if (Optind+1<argc && tar_re_search) { /* Doing regular expression seaches */
1794 if ((preg = (regex_t *)malloc(65536)) == NULL) {
1796 DEBUG(0, ("Could not allocate buffer for regular expression search\n"));
1801 if (errcode = regcomp(preg, argv[Optind + 1], REG_EXTENDED)) {
1805 errlen = regerror(errcode, preg, errstr, sizeof(errstr) - 1);
1807 DEBUG(0, ("Could not compile pattern buffer for re search: %s\n%s\n", argv[Optind + 1], errstr));
1813 clipn=argc-Optind-1;
1814 cliplist=argv+Optind+1;
1818 if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1819 /* Sets tar handle to either 0 or 1, as appropriate */
1820 tarhandle=(tar_type=='c');
1822 * Make sure that dbf points to stderr if we are using stdout for
1828 if (tar_type=='c' && (dry_run || strcmp(argv[Optind], "/dev/null")==0))
1831 DEBUG(0,("Output is /dev/null, assuming dry_run"));
1836 if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1)
1837 || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0))
1839 DEBUG(0,("Error opening local file %s - %s\n",
1840 argv[Optind], strerror(errno)));