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 int 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, int 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) {
723 DEBUG(3,("nread=%d\n",nread));
725 datalen = cli_read(cli, fnum, data, nread, read_size);
728 DEBUG(0,("Error reading file %s : %s\n", rname, cli_errstr(cli)));
732 /* add received bits of file to buffer - dotarbuf will
733 * write out in 512 byte intervals */
734 if (dotarbuf(tarhandle,data,datalen) != datalen) {
735 DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
741 DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
748 /* pad tar file with zero's if we couldn't get entire file */
749 if (nread < finfo.size) {
750 DEBUG(0, ("Didn't get entire file. size=%d, nread=%d\n", finfo.size, nread));
751 if (padit(data, sizeof(data), finfo.size - nread))
752 DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
755 /* round tar file to nearest block */
756 if (finfo.size % TBLOCK)
757 dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
759 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
763 cli_close(cli, fnum);
767 struct timeval tp_end;
770 /* if shallitime is true then we didn't skip */
771 if (tar_reset && !dry_run)
772 (void) do_setrattr(finfo.name, aARCH, ATTRRESET);
774 GetTimeOfDay(&tp_end);
776 (tp_end.tv_sec - tp_start.tv_sec)*1000 +
777 (tp_end.tv_usec - tp_start.tv_usec)/1000;
778 get_total_time_ms += this_time;
779 get_total_size += finfo.size;
783 DEBUG(0, ("%10d (%7.1f kb/s) %s\n",
784 finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
788 /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
789 DEBUG(3,("(%g kb/s) (average %g kb/s)\n",
790 finfo.size / MAX(0.001, (1.024*this_time)),
791 get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
795 /****************************************************************************
796 Append single file to tar file (or not)
797 ***************************************************************************/
798 static void do_tar(file_info *finfo)
802 if (strequal(finfo->name,"..") || strequal(finfo->name,"."))
805 /* Is it on the exclude list ? */
806 if (!tar_excl && clipn) {
809 DEBUG(5, ("Excl: strlen(cur_dir) = %i\n", strlen(cur_dir)));
811 safe_strcpy(exclaim, cur_dir, sizeof(pstring));
812 *(exclaim+strlen(exclaim)-1)='\0';
814 safe_strcat(exclaim, "\\", sizeof(pstring));
815 safe_strcat(exclaim, finfo->name, sizeof(exclaim));
817 DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
819 if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
821 (tar_re_search && !regexec(preg, exclaim, 0, NULL, 0))) {
823 (tar_re_search && mask_match(exclaim, cliplist[0], True, False))) {
825 DEBUG(3,("Skipping file %s\n", exclaim));
830 if (finfo->mode & aDIR)
832 pstring saved_curdir;
835 safe_strcpy(saved_curdir, cur_dir, sizeof(saved_curdir));
837 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));
839 safe_strcat(cur_dir,finfo->name, sizeof(cur_dir));
840 safe_strcat(cur_dir,"\\", sizeof(cur_dir));
842 DEBUG(5, ("Writing a dir, Name = %s\n", cur_dir));
844 /* write a tar directory, don't bother with mode - just set it to
846 writetarheader(tarhandle, cur_dir, 0, finfo->mtime, "040755 \0", '5');
848 DEBUG(0,(" directory %s\n", cur_dir));
850 ntarf++; /* Make sure we have a file on there */
851 safe_strcpy(mtar_mask,cur_dir, sizeof(pstring));
852 safe_strcat(mtar_mask,"*.*", sizeof(pstring));
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, 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> <perm=[+|-]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> <perm=[+|-]rsha>\n"));
1393 DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1394 (void) do_setrattr(fname, attra[ATTRSET], ATTRSET);
1395 (void) 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 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 do_list(tarmac,attribute,do_tar, False, True);
1476 safe_strcpy(mask,cur_dir, sizeof(pstring));
1477 safe_strcat(mask,"\\*.*", sizeof(pstring));
1478 do_list(mask,attribute,do_tar,False, True);
1481 if (ntarf) dotareof(tarhandle);
1485 DEBUG(0, ("tar: dumped %d tar files\n", ntarf));
1486 DEBUG(0, ("Total bytes written: %d\n", ttarf));
1490 if (must_free_cliplist) {
1492 for (i = 0; i < clipn; ++i) {
1498 must_free_cliplist = False;
1504 /****************************************************************************
1505 Find a token (filename) in a clip list
1506 ***************************************************************************/
1507 static int clipfind(char **aret, int ret, char *tok)
1509 if (aret==NULL) return 0;
1511 /* ignore leading slashes or dots in token */
1512 while(strchr("/\\.", *tok)) tok++;
1517 /* ignore leading slashes or dots in list */
1518 while(strchr("/\\.", *pkey)) pkey++;
1520 if (!strslashcmp(pkey, tok)) return 1;
1526 /****************************************************************************
1527 Read list of files to include from the file and initialize cliplist
1529 ***************************************************************************/
1530 static int read_inclusion_file(char *filename)
1532 FILE *inclusion = NULL;
1533 char buf[MAXPATHLEN + 1];
1534 char *inclusion_buffer = NULL;
1535 int inclusion_buffer_size = 0;
1536 int inclusion_buffer_sofar = 0;
1543 buf[MAXPATHLEN] = '\0'; /* guarantee null-termination */
1544 if ((inclusion = fopen(filename, "r")) == NULL) {
1545 /* XXX It would be better to include a reason for failure, but without
1546 * autoconf, it's hard to use strerror, sys_errlist, etc.
1548 DEBUG(0,("Unable to open inclusion file %s\n", filename));
1552 while ((! error) && (fgets(buf, sizeof(buf)-1, inclusion))) {
1553 if (inclusion_buffer == NULL) {
1554 inclusion_buffer_size = 1024;
1555 if ((inclusion_buffer = malloc(inclusion_buffer_size)) == NULL) {
1556 DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1562 if (buf[strlen(buf)-1] == '\n') {
1563 buf[strlen(buf)-1] = '\0';
1566 if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1567 inclusion_buffer_size *= 2;
1568 inclusion_buffer = Realloc(inclusion_buffer,inclusion_buffer_size);
1569 if (! inclusion_buffer) {
1570 DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1571 inclusion_buffer_size));
1577 safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
1578 inclusion_buffer_sofar += strlen(buf) + 1;
1584 /* Allocate an array of clipn + 1 char*'s for cliplist */
1585 cliplist = malloc((clipn + 1) * sizeof(char *));
1586 if (cliplist == NULL) {
1587 DEBUG(0,("failure allocating memory for cliplist\n"));
1590 cliplist[clipn] = NULL;
1591 p = inclusion_buffer;
1592 for (i = 0; (! error) && (i < clipn); i++) {
1593 /* set current item to NULL so array will be null-terminated even if
1594 * malloc fails below. */
1596 if ((tmpstr = (char *)malloc(strlen(p)+1)) == NULL) {
1597 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
1600 unfixtarname(tmpstr, p, strlen(p) + 1, True);
1601 cliplist[i] = tmpstr;
1602 if ((p = strchr(p, '\000')) == NULL) {
1603 DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1609 must_free_cliplist = True;
1613 if (inclusion_buffer) {
1614 free(inclusion_buffer);
1619 /* We know cliplist is always null-terminated */
1620 for (pp = cliplist; *pp; ++pp) {
1625 must_free_cliplist = False;
1630 /* cliplist and its elements are freed at the end of process_tar. */
1634 /****************************************************************************
1635 Parse tar arguments. Sets tar_type, tar_excl, etc.
1636 ***************************************************************************/
1637 int tar_parseargs(int argc, char *argv[], char *Optarg, int Optind)
1639 char tar_clipfl='\0';
1641 /* Reset back to defaults - could be from interactive version
1642 * reset mode and archive mode left as they are though
1654 if (tar_type=='c') {
1655 printf("Tar must be followed by only one of c or x.\n");
1661 if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1662 DEBUG(0,("Option b must be followed by valid blocksize\n"));
1673 DEBUG(0,("Option N must be followed by valid file name\n"));
1676 SMB_STRUCT_STAT stbuf;
1677 extern time_t newer_than;
1679 if (dos_stat(argv[Optind], &stbuf) == 0) {
1680 newer_than = stbuf.st_mtime;
1681 DEBUG(1,("Getting files newer than %s",
1682 asctime(LocalTime(&newer_than))));
1685 DEBUG(0,("Error setting newer-than time\n"));
1698 DEBUG(0,("Only one of I,X,F must be specified\n"));
1705 DEBUG(0,("Only one of I,X,F must be specified\n"));
1712 DEBUG(0,("Only one of I,X,F must be specified\n"));
1718 DEBUG(0, ("tar_re_search set\n"));
1719 tar_re_search = True;
1722 if (tar_type == 'c') {
1723 DEBUG(0, ("dry_run set\n"));
1726 DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1731 DEBUG(0,("Unknown tar option\n"));
1736 printf("Option T must be followed by one of c or x.\n");
1740 /* tar_excl is true if cliplist lists files to be included.
1741 * Both 'I' and 'F' mean include. */
1742 tar_excl=tar_clipfl!='X';
1744 if (tar_clipfl=='F') {
1745 if (argc-Optind-1 != 1) {
1746 DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1749 if (! read_inclusion_file(argv[Optind+1])) {
1752 } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
1757 cliplist=argv+Optind+1;
1758 clipn=argc-Optind-1;
1761 if ((tmplist=malloc(clipn*sizeof(char *))) == NULL) {
1762 DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n",
1768 for (clipcount = 0; clipcount < clipn; clipcount++) {
1770 DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1772 if ((tmpstr = (char *)malloc(strlen(cliplist[clipcount])+1)) == NULL) {
1773 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n",
1778 unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
1779 tmplist[clipcount] = tmpstr;
1780 DEBUG(5, ("Processed an item, %s\n", tmpstr));
1782 DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1785 must_free_cliplist = True;
1788 if (Optind+1<argc && tar_re_search) { /* Doing regular expression seaches */
1792 if ((preg = (regex_t *)malloc(65536)) == NULL) {
1794 DEBUG(0, ("Could not allocate buffer for regular expression search\n"));
1799 if (errcode = regcomp(preg, argv[Optind + 1], REG_EXTENDED)) {
1803 errlen = regerror(errcode, preg, errstr, sizeof(errstr) - 1);
1805 DEBUG(0, ("Could not compile pattern buffer for re search: %s\n%s\n", argv[Optind + 1], errstr));
1811 clipn=argc-Optind-1;
1812 cliplist=argv+Optind+1;
1816 if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1817 /* Sets tar handle to either 0 or 1, as appropriate */
1818 tarhandle=(tar_type=='c');
1820 if (tar_type=='c' && (dry_run || strcmp(argv[Optind], "/dev/null")==0))
1823 DEBUG(0,("Output is /dev/null, assuming dry_run"));
1828 if ((tar_type=='x' && (tarhandle = open(argv[Optind], O_RDONLY)) == -1)
1829 || (tar_type=='c' && (tarhandle=creat(argv[Optind], 0644)) < 0))
1831 DEBUG(0,("Error opening local file %s - %s\n",
1832 argv[Optind], strerror(errno)));