2 Unix SMB/CIFS implementation.
4 Copyright (C) Ricky Poulten 1995-1998
5 Copyright (C) Richard Sharpe 1998
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 /* The following changes developed by Richard Sharpe for Canon Information
22 Systems Research Australia (CISRA)
24 1. Restore can now restore files with long file names
25 2. Save now saves directory information so that we can restore
26 directory creation times
27 3. tar now accepts both UNIX path names and DOS path names. I prefer
28 those lovely /'s to those UGLY \'s :-)
29 4. the files to exclude can be specified as a regular expression by adding
30 an r flag to the other tar flags. Eg:
32 -TcrX file.tar "*.(obj|exe)"
34 will skip all .obj and .exe files
40 #include "client/client_proto.h"
42 static int clipfind(char **aret, int ret, char *tok);
44 typedef struct file_info_struct file_info2;
46 struct file_info_struct {
51 /* These times are normally kept in GMT */
55 char *name; /* This is dynamically allocate */
57 file_info2 *next, *prev; /* Used in the stack ... */
65 #define SEPARATORS " \t\n\r"
66 extern time_t newer_than;
67 extern struct cli_state *cli;
69 /* These defines are for the do_setrattr routine, to indicate
70 * setting and reseting of file attributes in the function call */
74 static uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
76 #ifndef CLIENT_TIMEOUT
77 #define CLIENT_TIMEOUT (30*1000)
80 static char *tarbuf, *buffer_p;
81 static int tp, ntarf, tbufsiz;
83 /* Incremental mode */
84 static BOOL tar_inc=False;
85 /* Reset archive bit */
86 static BOOL tar_reset=False;
87 /* Include / exclude mode (true=include, false=exclude) */
88 static BOOL tar_excl=True;
89 /* use regular expressions for search on file names */
90 static BOOL tar_re_search=False;
91 /* Do not dump anything, just calculate sizes */
92 static BOOL dry_run=False;
93 /* Dump files with System attribute */
94 static BOOL tar_system=True;
95 /* Dump files with Hidden attribute */
96 static BOOL tar_hidden=True;
97 /* Be noisy - make a catalogue */
98 static BOOL tar_noisy=True;
99 static BOOL tar_real_noisy=False; /* Don't want to be really noisy by default */
102 static char **cliplist=NULL;
104 static BOOL must_free_cliplist = False;
106 extern file_info def_finfo;
107 extern BOOL lowercase;
109 extern BOOL readbraw_supported;
111 extern pstring cur_dir;
112 extern int get_total_time_ms;
113 extern int get_total_size;
115 static int blocksize=20;
116 static int tarhandle;
118 static void writetarheader(int f, const char *aname, SMB_BIG_UINT size, time_t mtime,
119 const char *amode, unsigned char ftype);
120 static void do_atar(char *rname,char *lname,file_info *finfo1);
121 static void do_tar(file_info *finfo);
122 static void oct_it(SMB_BIG_UINT value, int ndgs, char *p);
123 static void fixtarname(char *tptr, const char *fp, size_t l);
124 static int dotarbuf(int f, char *b, int n);
125 static void dozerobuf(int f, int n);
126 static void dotareof(int f);
127 static void initarbuf(void);
129 /* restore functions */
130 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix);
131 static long unoct(char *p, int ndgs);
132 static void do_tarput(void);
133 static void unfixtarname(char *tptr, char *fp, int l, BOOL first);
136 * tar specific utitlities
139 /*******************************************************************
140 Create a string of size size+1 (for the null)
141 *******************************************************************/
143 static char *string_create_s(int size)
147 tmp = (char *)SMB_MALLOC(size+1);
150 DEBUG(0, ("Out of memory in string_create_s\n"));
156 /****************************************************************************
157 Write a tar header to buffer
158 ****************************************************************************/
160 static void writetarheader(int f, const char *aname, SMB_BIG_UINT size, time_t mtime,
161 const char *amode, unsigned char ftype)
167 DEBUG(5, ("WriteTarHdr, Type = %c, Size= %.0f, Name = %s\n", ftype, (double)size, aname));
169 memset(hb.dummy, 0, sizeof(hb.dummy));
172 /* We will be prepending a '.' in fixtarheader so use +2 to
173 * take care of the . and terminating zero. JRA.
176 /* write a GNU tar style long header */
178 b = (char *)SMB_MALLOC(l+TBLOCK+100);
180 DEBUG(0,("out of memory\n"));
183 writetarheader(f, "/./@LongLink", l+2, 0, " 0 \0", 'L');
184 memset(b, 0, l+TBLOCK+100);
185 fixtarname(b, aname, l+2);
187 DEBUG(5, ("File name in tar file: %s, size=%d, \n", b, (int)strlen(b)));
188 dotarbuf(f, b, TBLOCK*(((i-1)/TBLOCK)+1));
192 fixtarname(hb.dbuf.name, aname, (l+2 >= NAMSIZ) ? NAMSIZ : l + 2);
195 strlower_m(hb.dbuf.name);
197 /* write out a "standard" tar format header */
199 hb.dbuf.name[NAMSIZ-1]='\0';
200 safe_strcpy(hb.dbuf.mode, amode, sizeof(hb.dbuf.mode)-1);
201 oct_it((SMB_BIG_UINT)0, 8, hb.dbuf.uid);
202 oct_it((SMB_BIG_UINT)0, 8, hb.dbuf.gid);
203 oct_it((SMB_BIG_UINT) size, 13, hb.dbuf.size);
205 if (size > (SMB_BIG_UINT)077777777777LL) {
207 if (size > (SMB_BIG_UINT)077777777777) {
210 /* This is a non-POSIX compatible extention to store files
213 memset(hb.dbuf.size, 0, 4);
215 for (i = 8, jp=(char*)&size; i; i--)
216 hb.dbuf.size[i+3] = *(jp++);
218 oct_it((SMB_BIG_UINT) mtime, 13, hb.dbuf.mtime);
219 memcpy(hb.dbuf.chksum, " ", sizeof(hb.dbuf.chksum));
220 memset(hb.dbuf.linkname, 0, NAMSIZ);
221 hb.dbuf.linkflag=ftype;
223 for (chk=0, i=sizeof(hb.dummy), jp=hb.dummy; --i>=0;)
226 oct_it((SMB_BIG_UINT) chk, 8, hb.dbuf.chksum);
227 hb.dbuf.chksum[6] = '\0';
229 (void) dotarbuf(f, hb.dummy, sizeof(hb.dummy));
232 /****************************************************************************
233 Read a tar header into a hblock structure, and validate
234 ***************************************************************************/
236 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix)
243 * read in a "standard" tar format header - we're not that interested
244 * in that many fields, though
247 /* check the checksum */
248 for (chk=0, i=sizeof(hb->dummy), jp=hb->dummy; --i>=0;)
254 /* compensate for blanks in chksum header */
255 for (i=sizeof(hb->dbuf.chksum), jp=hb->dbuf.chksum; --i>=0;)
258 chk += ' ' * sizeof(hb->dbuf.chksum);
260 fchk=unoct(hb->dbuf.chksum, sizeof(hb->dbuf.chksum));
262 DEBUG(5, ("checksum totals chk=%ld fchk=%ld chksum=%s\n",
263 chk, fchk, hb->dbuf.chksum));
266 DEBUG(0, ("checksums don't match %ld %ld\n", fchk, chk));
267 dump_data(5, (char *)hb - TBLOCK, TBLOCK *3);
271 if ((finfo->name = string_create_s(strlen(prefix) + strlen(hb -> dbuf.name) + 3)) == NULL) {
272 DEBUG(0, ("Out of space creating file_info2 for %s\n", hb -> dbuf.name));
276 safe_strcpy(finfo->name, prefix, strlen(prefix) + strlen(hb -> dbuf.name) + 3);
278 /* use l + 1 to do the null too; do prefix - prefcnt to zap leading slash */
279 unfixtarname(finfo->name + strlen(prefix), hb->dbuf.name,
280 strlen(hb->dbuf.name) + 1, True);
282 /* can't handle some links at present */
283 if ((hb->dbuf.linkflag != '0') && (hb -> dbuf.linkflag != '5')) {
284 if (hb->dbuf.linkflag == 0) {
285 DEBUG(6, ("Warning: NULL link flag (gnu tar archive ?) %s\n",
288 if (hb -> dbuf.linkflag == 'L') { /* We have a longlink */
289 /* Do nothing here at the moment. do_tarput will handle this
290 as long as the longlink gets back to it, as it has to advance
291 the buffer pointer, etc */
293 DEBUG(0, ("this tar file appears to contain some kind \
294 of link other than a GNUtar Longlink - ignoring\n"));
300 if ((unoct(hb->dbuf.mode, sizeof(hb->dbuf.mode)) & S_IFDIR) ||
301 (*(finfo->name+strlen(finfo->name)-1) == '\\')) {
304 finfo->mode=0; /* we don't care about mode at the moment, we'll
305 * just make it a regular file */
309 * Bug fix by richard@sj.co.uk
311 * REC: restore times correctly (as does tar)
312 * We only get the modification time of the file; set the creation time
313 * from the mod. time, and the access time to current time
315 finfo->mtime = finfo->ctime = strtol(hb->dbuf.mtime, NULL, 8);
316 finfo->atime = time(NULL);
317 finfo->size = unoct(hb->dbuf.size, sizeof(hb->dbuf.size));
322 /****************************************************************************
323 Write out the tar buffer to tape or wherever
324 ****************************************************************************/
326 static int dotarbuf(int f, char *b, int n)
333 /* This routine and the next one should be the only ones that do write()s */
334 if (tp + n >= tbufsiz) {
338 memcpy(tarbuf + tp, b, diff);
339 fail=fail && (1+write(f, tarbuf, tbufsiz));
344 while (n >= tbufsiz) {
345 fail=fail && (1 + write(f, b, tbufsiz));
352 memcpy(tarbuf+tp, b, n);
356 return(fail ? writ : 0);
359 /****************************************************************************
360 Write zeros to buffer / tape
361 ****************************************************************************/
363 static void dozerobuf(int f, int n)
365 /* short routine just to write out n zeros to buffer -
366 * used to round files to nearest block
367 * and to do tar EOFs */
372 if (n+tp >= tbufsiz) {
373 memset(tarbuf+tp, 0, tbufsiz-tp);
374 write(f, tarbuf, tbufsiz);
375 memset(tarbuf, 0, (tp+=n-tbufsiz));
377 memset(tarbuf+tp, 0, n);
382 /****************************************************************************
384 ****************************************************************************/
386 static void initarbuf(void)
388 /* initialize tar buffer */
389 tbufsiz=blocksize*TBLOCK;
390 tarbuf=SMB_MALLOC(tbufsiz); /* FIXME: We might not get the buffer */
392 /* reset tar buffer pointer and tar file counter and total dumped */
393 tp=0; ntarf=0; ttarf=0;
396 /****************************************************************************
397 Write two zero blocks at end of file
398 ****************************************************************************/
400 static void dotareof(int f)
402 SMB_STRUCT_STAT stbuf;
403 /* Two zero blocks at end of file, write out full buffer */
408 (void) dozerobuf(f, TBLOCK);
409 (void) dozerobuf(f, TBLOCK);
411 if (sys_fstat(f, &stbuf) == -1) {
412 DEBUG(0, ("Couldn't stat file handle\n"));
416 /* Could be a pipe, in which case S_ISREG should fail,
417 * and we should write out at full size */
419 write(f, tarbuf, S_ISREG(stbuf.st_mode) ? tp : tbufsiz);
422 /****************************************************************************
423 (Un)mangle DOS pathname, make nonabsolute
424 ****************************************************************************/
426 static void fixtarname(char *tptr, const char *fp, size_t l)
428 /* add a '.' to start of file name, convert from ugly dos \'s in path
429 * to lovely unix /'s :-} */
433 StrnCpy(tptr, fp, l-1);
434 string_replace(tptr, '\\', '/');
437 /****************************************************************************
438 Convert from decimal to octal string
439 ****************************************************************************/
441 static void oct_it (SMB_BIG_UINT value, int ndgs, char *p)
443 /* Converts long to octal string, pads with leading zeros */
445 /* skip final null, but do final space */
449 /* Loop does at least one digit */
451 p[--ndgs] = '0' + (char) (value & 7);
453 } while (ndgs > 0 && value != 0);
455 /* Do leading zeros */
460 /****************************************************************************
461 Convert from octal string to long
462 ***************************************************************************/
464 static long unoct(char *p, int ndgs)
467 /* Converts octal string to long, ignoring any non-digit */
470 if (isdigit((int)*p))
471 value = (value << 3) | (long) (*p - '0');
479 /****************************************************************************
480 Compare two strings in a slash insensitive way, allowing s1 to match s2
481 if s1 is an "initial" string (up to directory marker). Thus, if s2 is
482 a file in any subdirectory of s1, declare a match.
483 ***************************************************************************/
485 static int strslashcmp(char *s1, char *s2)
489 while(*s1 && *s2 && (*s1 == *s2 || tolower_ascii(*s1) == tolower_ascii(*s2) ||
490 (*s1 == '\\' && *s2=='/') || (*s1 == '/' && *s2=='\\'))) {
494 /* if s1 has a trailing slash, it compared equal, so s1 is an "initial"
497 if (!*s1 && s1 != s1_0 && (*(s1-1) == '/' || *(s1-1) == '\\'))
500 /* ignore trailing slash on s1 */
501 if (!*s2 && (*s1 == '/' || *s1 == '\\') && !*(s1+1))
504 /* check for s1 is an "initial" string of s2 */
505 if ((*s2 == '/' || *s2 == '\\') && !*s1)
511 /****************************************************************************
512 Ensure a remote path exists (make if necessary)
513 ***************************************************************************/
515 static BOOL ensurepath(char *fname)
517 /* *must* be called with buffer ready malloc'ed */
518 /* ensures path exists */
520 char *partpath, *ffname;
521 char *p=fname, *basehack;
523 DEBUG(5, ( "Ensurepath called with: %s\n", fname));
525 partpath = string_create_s(strlen(fname));
526 ffname = string_create_s(strlen(fname));
528 if ((partpath == NULL) || (ffname == NULL)){
529 DEBUG(0, ("Out of memory in ensurepath: %s\n", fname));
537 /* fname copied to ffname so can strtok */
539 safe_strcpy(ffname, fname, strlen(fname));
541 /* do a `basename' on ffname, so don't try and make file name directory */
542 if ((basehack=strrchr_m(ffname, '\\')) == NULL)
547 p=strtok(ffname, "\\");
550 safe_strcat(partpath, p, strlen(fname) + 1);
552 if (!cli_chkpath(cli, partpath)) {
553 if (!cli_mkdir(cli, partpath)) {
554 DEBUG(0, ("Error mkdirhiering\n"));
557 DEBUG(3, ("mkdirhiering %s\n", partpath));
561 safe_strcat(partpath, "\\", strlen(fname) + 1);
562 p = strtok(NULL,"/\\");
568 static int padit(char *buf, SMB_BIG_UINT bufsize, SMB_BIG_UINT padsize)
573 DEBUG(5, ("Padding with %0.f zeros\n", (double)padsize));
574 memset(buf, 0, (size_t)bufsize);
575 while( !berr && padsize > 0 ) {
576 bytestowrite= (int)MIN(bufsize, padsize);
577 berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite;
578 padsize -= bytestowrite;
584 static void do_setrattr(char *name, uint16 attr, int set)
588 if (!cli_getatr(cli, name, &oldattr, NULL, NULL)) return;
590 if (set == ATTRSET) {
593 attr = oldattr & ~attr;
596 if (!cli_setatr(cli, name, attr, 0)) {
597 DEBUG(1,("setatr failed: %s\n", cli_errstr(cli)));
601 /****************************************************************************
602 append one remote file to the tar file
603 ***************************************************************************/
605 static void do_atar(char *rname,char *lname,file_info *finfo1)
608 SMB_BIG_UINT nread=0;
611 BOOL close_done = False;
612 BOOL shallitime=True;
614 int read_size = 65520;
617 struct timeval tp_start;
619 GetTimeOfDay(&tp_start);
621 ftype = '0'; /* An ordinary file ... */
624 finfo.size = finfo1 -> size;
625 finfo.mode = finfo1 -> mode;
626 finfo.uid = finfo1 -> uid;
627 finfo.gid = finfo1 -> gid;
628 finfo.mtime = finfo1 -> mtime;
629 finfo.atime = finfo1 -> atime;
630 finfo.ctime = finfo1 -> ctime;
631 finfo.name = finfo1 -> name;
633 finfo.size = def_finfo.size;
634 finfo.mode = def_finfo.mode;
635 finfo.uid = def_finfo.uid;
636 finfo.gid = def_finfo.gid;
637 finfo.mtime = def_finfo.mtime;
638 finfo.atime = def_finfo.atime;
639 finfo.ctime = def_finfo.ctime;
640 finfo.name = def_finfo.name;
644 DEBUG(3,("skipping file %s of size %12.0f bytes\n", finfo.name,
645 (double)finfo.size));
647 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
652 fnum = cli_open(cli, rname, O_RDONLY, DENY_NONE);
654 dos_clean_name(rname);
657 DEBUG(0,("%s opening remote file %s (%s)\n",
658 cli_errstr(cli),rname, cur_dir));
662 finfo.name = string_create_s(strlen(rname));
663 if (finfo.name == NULL) {
664 DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n"));
668 safe_strcpy(finfo.name,rname, strlen(rname));
670 if (!cli_getattrE(cli, fnum, &finfo.mode, &finfo.size, NULL, &finfo.atime, &finfo.mtime)) {
671 DEBUG(0, ("getattrE: %s\n", cli_errstr(cli)));
674 finfo.ctime = finfo.mtime;
677 DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
679 if (tar_inc && !(finfo.mode & aARCH)) {
680 DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
682 } else if (!tar_system && (finfo.mode & aSYSTEM)) {
683 DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
685 } else if (!tar_hidden && (finfo.mode & aHIDDEN)) {
686 DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
689 BOOL wrote_tar_header = False;
691 DEBUG(3,("getting file %s of size %.0f bytes as a tar file %s",
692 finfo.name, (double)finfo.size, lname));
694 while (nread < finfo.size && !close_done) {
696 DEBUG(3,("nread=%.0f\n",(double)nread));
698 datalen = cli_read(cli, fnum, data, nread, read_size);
701 DEBUG(0,("Error reading file %s : %s\n", rname, cli_errstr(cli)));
707 /* Only if the first read succeeds, write out the tar header. */
708 if (!wrote_tar_header) {
709 /* write a tar header, don't bother with mode - just set to 100644 */
710 writetarheader(tarhandle, rname, finfo.size, finfo.mtime, "100644 \0", ftype);
711 wrote_tar_header = True;
714 /* if file size has increased since we made file size query, truncate
715 read so tar header for this file will be correct.
718 if (nread > finfo.size) {
719 datalen -= nread - finfo.size;
720 DEBUG(0,("File size change - truncating %s to %.0f bytes\n",
721 finfo.name, (double)finfo.size));
724 /* add received bits of file to buffer - dotarbuf will
725 * write out in 512 byte intervals */
727 if (dotarbuf(tarhandle,data,datalen) != datalen) {
728 DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
733 DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
740 if (wrote_tar_header) {
741 /* pad tar file with zero's if we couldn't get entire file */
742 if (nread < finfo.size) {
743 DEBUG(0, ("Didn't get entire file. size=%.0f, nread=%d\n",
744 (double)finfo.size, (int)nread));
745 if (padit(data, (SMB_BIG_UINT)sizeof(data), finfo.size - nread))
746 DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
749 /* round tar file to nearest block */
750 if (finfo.size % TBLOCK)
751 dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
753 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
756 DEBUG(4, ("skipping %s - initial read failed (file was locked ?)\n", finfo.name));
761 cli_close(cli, fnum);
764 struct timeval tp_end;
767 /* if shallitime is true then we didn't skip */
768 if (tar_reset && !dry_run)
769 (void) do_setrattr(finfo.name, aARCH, ATTRRESET);
771 GetTimeOfDay(&tp_end);
772 this_time = (tp_end.tv_sec - tp_start.tv_sec)*1000 + (tp_end.tv_usec - tp_start.tv_usec)/1000;
773 get_total_time_ms += this_time;
774 get_total_size += finfo.size;
777 DEBUG(0, ("%12.0f (%7.1f kb/s) %s\n",
778 (double)finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
782 /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
783 DEBUG(3,("(%g kb/s) (average %g kb/s)\n",
784 finfo.size / MAX(0.001, (1.024*this_time)),
785 get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
789 /****************************************************************************
790 Append single file to tar file (or not)
791 ***************************************************************************/
793 static void do_tar(file_info *finfo)
797 if (strequal(finfo->name,"..") || strequal(finfo->name,"."))
800 /* Is it on the exclude list ? */
801 if (!tar_excl && clipn) {
804 DEBUG(5, ("Excl: strlen(cur_dir) = %d\n", (int)strlen(cur_dir)));
806 pstrcpy(exclaim, cur_dir);
807 *(exclaim+strlen(exclaim)-1)='\0';
809 pstrcat(exclaim, "\\");
810 pstrcat(exclaim, finfo->name);
812 DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
814 if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
815 (tar_re_search && mask_match_list(exclaim, cliplist, clipn, True))) {
816 DEBUG(3,("Skipping file %s\n", exclaim));
821 if (finfo->mode & aDIR) {
822 pstring saved_curdir;
825 pstrcpy(saved_curdir, cur_dir);
827 DEBUG(5, ("Sizeof(cur_dir)=%d, strlen(cur_dir)=%d, \
828 strlen(finfo->name)=%d\nname=%s,cur_dir=%s\n",
829 (int)sizeof(cur_dir), (int)strlen(cur_dir),
830 (int)strlen(finfo->name), finfo->name, cur_dir));
832 pstrcat(cur_dir,finfo->name);
833 pstrcat(cur_dir,"\\");
835 DEBUG(5, ("Writing a dir, Name = %s\n", cur_dir));
837 /* write a tar directory, don't bother with mode - just set it to
839 writetarheader(tarhandle, cur_dir, 0, finfo->mtime, "040755 \0", '5');
841 DEBUG(0,(" directory %s\n", cur_dir));
843 ntarf++; /* Make sure we have a file on there */
844 pstrcpy(mtar_mask,cur_dir);
845 pstrcat(mtar_mask,"*");
846 DEBUG(5, ("Doing list with mtar_mask: %s\n", mtar_mask));
847 do_list(mtar_mask, attribute, do_tar, False, True);
848 pstrcpy(cur_dir,saved_curdir);
850 pstrcpy(rname,cur_dir);
851 pstrcat(rname,finfo->name);
852 do_atar(rname,finfo->name,finfo);
856 /****************************************************************************
857 Convert from UNIX to DOS file names
858 ***************************************************************************/
860 static void unfixtarname(char *tptr, char *fp, int l, BOOL first)
862 /* remove '.' from start of file name, convert from unix /'s to
863 * dos \'s in path. Kill any absolute path names. But only if first!
866 DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
873 if (*fp == '\\' || *fp == '/') {
879 safe_strcpy(tptr, fp, l);
880 string_replace(tptr, '/', '\\');
883 /****************************************************************************
884 Move to the next block in the buffer, which may mean read in another set of
885 blocks. FIXME, we should allow more than one block to be skipped.
886 ****************************************************************************/
888 static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
890 int bufread, total = 0;
892 DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp));
896 if (*bufferp >= (ltarbuf + bufsiz)) {
898 DEBUG(5, ("Reading more data into ltarbuf ...\n"));
901 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>
902 * Fixes bug where read can return short if coming from
906 bufread = read(tarhandle, ltarbuf, bufsiz);
909 while (total < bufsiz) {
910 if (bufread < 0) { /* An error, return false */
911 return (total > 0 ? -2 : bufread);
919 bufread = read(tarhandle, <arbuf[total], bufsiz - total);
923 DEBUG(5, ("Total bytes read ... %i\n", total));
931 /* Skip a file, even if it includes a long file name? */
932 static int skip_file(int skipsize)
934 int dsize = skipsize;
936 DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
938 /* FIXME, we should skip more than one block at a time */
941 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
942 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
951 /*************************************************************
952 Get a file from the tar file and store it.
953 When this is called, tarbuf already contains the first
954 file block. This is a bit broken & needs fixing.
955 **************************************************************/
957 static int get_file(file_info2 finfo)
959 int fnum = -1, pos = 0, dsize = 0, bpos = 0;
960 SMB_BIG_UINT rsize = 0;
962 DEBUG(5, ("get_file: file: %s, size %.0f\n", finfo.name, (double)finfo.size));
964 if (ensurepath(finfo.name) &&
965 (fnum=cli_open(cli, finfo.name, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE)) == -1) {
966 DEBUG(0, ("abandoning restore\n"));
970 /* read the blocks from the tar file and write to the remote file */
972 rsize = finfo.size; /* This is how much to write */
976 /* We can only write up to the end of the buffer */
977 dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, 65520); /* Calculate the size to write */
978 dsize = MIN(dsize, rsize); /* Should be only what is left */
979 DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos));
981 if (cli_write(cli, fnum, 0, buffer_p + bpos, pos, dsize) != dsize) {
982 DEBUG(0, ("Error writing remote file\n"));
989 /* Now figure out how much to move in the buffer */
991 /* FIXME, we should skip more than one block at a time */
993 /* First, skip any initial part of the part written that is left over */
994 /* from the end of the first TBLOCK */
996 if ((bpos) && ((bpos + dsize) >= TBLOCK)) {
997 dsize -= (TBLOCK - bpos); /* Get rid of the end of the first block */
1000 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) { /* and skip the block */
1001 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1007 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>.
1008 * If the file being extracted is an exact multiple of
1009 * TBLOCK bytes then we don't want to extract the next
1010 * block from the tarfile here, as it will be done in
1011 * the caller of get_file().
1014 while (((rsize != 0) && (dsize >= TBLOCK)) ||
1015 ((rsize == 0) && (dsize > TBLOCK))) {
1017 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1018 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1027 /* Now close the file ... */
1029 if (!cli_close(cli, fnum)) {
1030 DEBUG(0, ("Error closing remote file\n"));
1034 /* Now we update the creation date ... */
1035 DEBUG(5, ("Updating creation date on %s\n", finfo.name));
1037 if (!cli_setatr(cli, finfo.name, finfo.mode, finfo.mtime)) {
1038 if (tar_real_noisy) {
1039 DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
1040 /*return(False); */ /* Ignore, as Win95 does not allow changes */
1045 DEBUG(0, ("restore tar file %s of size %.0f bytes\n", finfo.name, (double)finfo.size));
1049 /* Create a directory. We just ensure that the path exists and return as there
1050 is no file associated with a directory
1052 static int get_dir(file_info2 finfo)
1054 DEBUG(0, ("restore directory %s\n", finfo.name));
1056 if (!ensurepath(finfo.name)) {
1057 DEBUG(0, ("Problems creating directory\n"));
1064 /* Get a file with a long file name ... first file has file name, next file
1065 has the data. We only want the long file name, as the loop in do_tarput
1066 will deal with the rest.
1068 static char *get_longfilename(file_info2 finfo)
1070 /* finfo.size here is the length of the filename as written by the "/./@LongLink" name
1072 int namesize = finfo.size + strlen(cur_dir) + 2;
1073 char *longname = SMB_MALLOC(namesize);
1074 int offset = 0, left = finfo.size;
1077 DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
1078 DEBUG(5, ("Len = %.0f\n", (double)finfo.size));
1080 if (longname == NULL) {
1081 DEBUG(0, ("could not allocate buffer of size %d for longname\n", namesize));
1085 /* First, add cur_dir to the long file name */
1087 if (strlen(cur_dir) > 0) {
1088 strncpy(longname, cur_dir, namesize);
1089 offset = strlen(cur_dir);
1092 /* Loop through the blocks picking up the name */
1095 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1096 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1097 SAFE_FREE(longname);
1101 unfixtarname(longname + offset, buffer_p, MIN(TBLOCK, finfo.size), first--);
1102 DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
1111 static void do_tarput(void)
1114 struct timeval tp_start;
1115 char *longfilename = NULL, linkflag;
1120 GetTimeOfDay(&tp_start);
1121 DEBUG(5, ("RJS do_tarput called ...\n"));
1123 buffer_p = tarbuf + tbufsiz; /* init this to force first read */
1125 /* Now read through those files ... */
1127 /* Get us to the next block, or the first block first time around */
1128 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1129 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1130 SAFE_FREE(longfilename);
1134 DEBUG(5, ("Reading the next header ...\n"));
1136 switch (readtarheader((union hblock *) buffer_p, &finfo, cur_dir)) {
1137 case -2: /* Hmm, not good, but not fatal */
1138 DEBUG(0, ("Skipping %s...\n", finfo.name));
1139 if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) && !skip_file(finfo.size)) {
1140 DEBUG(0, ("Short file, bailing out...\n"));
1146 DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
1149 case 0: /* chksum is zero - looks like an EOF */
1150 DEBUG(0, ("tar: restored %d files and directories\n", ntarf));
1151 return; /* Hmmm, bad here ... */
1158 /* Now, do we have a long file name? */
1159 if (longfilename != NULL) {
1160 SAFE_FREE(finfo.name); /* Free the space already allocated */
1161 finfo.name = longfilename;
1162 longfilename = NULL;
1165 /* Well, now we have a header, process the file ... */
1166 /* Should we skip the file? We have the long name as well here */
1167 skip = clipn && ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl) ||
1168 (tar_re_search && mask_match_list(finfo.name, cliplist, clipn, True)));
1170 DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
1172 skip_file(finfo.size);
1176 /* We only get this far if we should process the file */
1177 linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
1179 case '0': /* Should use symbolic names--FIXME */
1181 * Skip to the next block first, so we can get the file, FIXME, should
1182 * be in get_file ...
1183 * The 'finfo.size != 0' fix is from Bob Boehmer <boehmer@worldnet.att.net>
1184 * Fixes bug where file size in tarfile is zero.
1186 if ((finfo.size != 0) && next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1187 DEBUG(0, ("Short file, bailing out...\n"));
1190 if (!get_file(finfo)) {
1191 DEBUG(0, ("Abandoning restore\n"));
1196 if (!get_dir(finfo)) {
1197 DEBUG(0, ("Abandoning restore \n"));
1202 SAFE_FREE(longfilename);
1203 longfilename = get_longfilename(finfo);
1204 if (!longfilename) {
1205 DEBUG(0, ("abandoning restore\n"));
1208 DEBUG(5, ("Long file name: %s\n", longfilename));
1212 skip_file(finfo.size); /* Don't handle these yet */
1219 * samba interactive commands
1222 /****************************************************************************
1224 ***************************************************************************/
1231 if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1232 DEBUG(0, ("blocksize <n>\n"));
1237 if (block < 0 || block > 65535) {
1238 DEBUG(0, ("blocksize out of range"));
1243 DEBUG(2,("blocksize is now %d\n", blocksize));
1248 /****************************************************************************
1249 command to set incremental / reset mode
1250 ***************************************************************************/
1252 int cmd_tarmode(void)
1256 while (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1257 if (strequal(buf, "full"))
1259 else if (strequal(buf, "inc"))
1261 else if (strequal(buf, "reset"))
1263 else if (strequal(buf, "noreset"))
1265 else if (strequal(buf, "system"))
1267 else if (strequal(buf, "nosystem"))
1269 else if (strequal(buf, "hidden"))
1271 else if (strequal(buf, "nohidden"))
1273 else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
1275 else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
1278 DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
1281 DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
1282 tar_inc ? "incremental" : "full",
1283 tar_system ? "system" : "nosystem",
1284 tar_hidden ? "hidden" : "nohidden",
1285 tar_reset ? "reset" : "noreset",
1286 tar_noisy ? "verbose" : "quiet"));
1290 /****************************************************************************
1291 Feeble attrib command
1292 ***************************************************************************/
1294 int cmd_setmode(void)
1302 attra[0] = attra[1] = 0;
1304 if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1305 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1309 pstrcpy(fname, cur_dir);
1310 pstrcat(fname, buf);
1312 while (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1324 attra[direct]|=aRONLY;
1327 attra[direct]|=aHIDDEN;
1330 attra[direct]|=aSYSTEM;
1333 attra[direct]|=aARCH;
1336 DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1342 if (attra[ATTRSET]==0 && attra[ATTRRESET]==0) {
1343 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1347 DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1348 do_setrattr(fname, attra[ATTRSET], ATTRSET);
1349 do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
1353 /****************************************************************************
1354 Principal command for creating / extracting
1355 ***************************************************************************/
1364 if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1365 DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
1369 argl=toktocliplist(&argcl, NULL);
1370 if (!tar_parseargs(argcl, argl, buf, 0))
1373 ret = process_tar();
1378 /****************************************************************************
1379 Command line (option) version
1380 ***************************************************************************/
1382 int process_tar(void)
1399 if (clipn && tar_excl) {
1403 for (i=0; i<clipn; i++) {
1404 DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
1406 if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1407 *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1410 if (strrchr_m(cliplist[i], '\\')) {
1413 pstrcpy(saved_dir, cur_dir);
1415 if (*cliplist[i]=='\\') {
1416 pstrcpy(tarmac, cliplist[i]);
1418 pstrcpy(tarmac, cur_dir);
1419 pstrcat(tarmac, cliplist[i]);
1421 pstrcpy(cur_dir, tarmac);
1422 *(strrchr_m(cur_dir, '\\')+1)='\0';
1424 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1425 do_list(tarmac,attribute,do_tar, False, True);
1426 pstrcpy(cur_dir,saved_dir);
1428 pstrcpy(tarmac, cur_dir);
1429 pstrcat(tarmac, cliplist[i]);
1430 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1431 do_list(tarmac,attribute,do_tar, False, True);
1436 pstrcpy(mask,cur_dir);
1437 DEBUG(5, ("process_tar, do_list with mask: %s\n", mask));
1438 pstrcat(mask,"\\*");
1439 do_list(mask,attribute,do_tar,False, True);
1443 dotareof(tarhandle);
1447 DEBUG(0, ("tar: dumped %d files and directories\n", ntarf));
1448 DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf));
1452 if (must_free_cliplist) {
1454 for (i = 0; i < clipn; ++i) {
1455 SAFE_FREE(cliplist[i]);
1457 SAFE_FREE(cliplist);
1460 must_free_cliplist = False;
1465 /****************************************************************************
1466 Find a token (filename) in a clip list
1467 ***************************************************************************/
1469 static int clipfind(char **aret, int ret, char *tok)
1474 /* ignore leading slashes or dots in token */
1475 while(strchr_m("/\\.", *tok))
1481 /* ignore leading slashes or dots in list */
1482 while(strchr_m("/\\.", *pkey))
1485 if (!strslashcmp(pkey, tok))
1491 /****************************************************************************
1492 Read list of files to include from the file and initialize cliplist
1494 ***************************************************************************/
1496 static int read_inclusion_file(char *filename)
1498 XFILE *inclusion = NULL;
1499 char buf[PATH_MAX + 1];
1500 char *inclusion_buffer = NULL;
1501 int inclusion_buffer_size = 0;
1502 int inclusion_buffer_sofar = 0;
1509 buf[PATH_MAX] = '\0'; /* guarantee null-termination */
1510 if ((inclusion = x_fopen(filename, O_RDONLY, 0)) == NULL) {
1511 /* XXX It would be better to include a reason for failure, but without
1512 * autoconf, it's hard to use strerror, sys_errlist, etc.
1514 DEBUG(0,("Unable to open inclusion file %s\n", filename));
1518 while ((! error) && (x_fgets(buf, sizeof(buf)-1, inclusion))) {
1519 if (inclusion_buffer == NULL) {
1520 inclusion_buffer_size = 1024;
1521 if ((inclusion_buffer = SMB_MALLOC(inclusion_buffer_size)) == NULL) {
1522 DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1528 if (buf[strlen(buf)-1] == '\n') {
1529 buf[strlen(buf)-1] = '\0';
1532 if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1533 inclusion_buffer_size *= 2;
1534 inclusion_buffer = SMB_REALLOC(inclusion_buffer,inclusion_buffer_size);
1535 if (!inclusion_buffer) {
1536 DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1537 inclusion_buffer_size));
1543 safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
1544 inclusion_buffer_sofar += strlen(buf) + 1;
1547 x_fclose(inclusion);
1550 /* Allocate an array of clipn + 1 char*'s for cliplist */
1551 cliplist = SMB_MALLOC_ARRAY(char *, clipn + 1);
1552 if (cliplist == NULL) {
1553 DEBUG(0,("failure allocating memory for cliplist\n"));
1556 cliplist[clipn] = NULL;
1557 p = inclusion_buffer;
1558 for (i = 0; (! error) && (i < clipn); i++) {
1559 /* set current item to NULL so array will be null-terminated even if
1560 * malloc fails below. */
1562 if ((tmpstr = (char *)SMB_MALLOC(strlen(p)+1)) == NULL) {
1563 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
1566 unfixtarname(tmpstr, p, strlen(p) + 1, True);
1567 cliplist[i] = tmpstr;
1568 if ((p = strchr_m(p, '\000')) == NULL) {
1569 DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1575 must_free_cliplist = True;
1579 SAFE_FREE(inclusion_buffer);
1583 /* We know cliplist is always null-terminated */
1584 for (pp = cliplist; *pp; ++pp) {
1587 SAFE_FREE(cliplist);
1589 must_free_cliplist = False;
1594 /* cliplist and its elements are freed at the end of process_tar. */
1598 /****************************************************************************
1599 Parse tar arguments. Sets tar_type, tar_excl, etc.
1600 ***************************************************************************/
1602 int tar_parseargs(int argc, char *argv[], const char *Optarg, int Optind)
1604 int newOptind = Optind;
1605 char tar_clipfl='\0';
1607 /* Reset back to defaults - could be from interactive version
1608 * reset mode and archive mode left as they are though
1620 if (tar_type=='c') {
1621 printf("Tar must be followed by only one of c or x.\n");
1627 if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1628 DEBUG(0,("Option b must be followed by valid blocksize\n"));
1640 DEBUG(0,("Option N must be followed by valid file name\n"));
1643 SMB_STRUCT_STAT stbuf;
1645 if (sys_stat(argv[Optind], &stbuf) == 0) {
1646 newer_than = stbuf.st_mtime;
1647 DEBUG(1,("Getting files newer than %s",
1648 time_to_asc(&newer_than)));
1652 DEBUG(0,("Error setting newer-than time\n"));
1665 DEBUG(0,("Only one of I,X,F must be specified\n"));
1672 DEBUG(0,("Only one of I,X,F must be specified\n"));
1679 DEBUG(0,("Only one of I,X,F must be specified\n"));
1685 DEBUG(0, ("tar_re_search set\n"));
1686 tar_re_search = True;
1689 if (tar_type == 'c') {
1690 DEBUG(0, ("dry_run set\n"));
1693 DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1698 DEBUG(0,("Unknown tar option\n"));
1704 printf("Option T must be followed by one of c or x.\n");
1708 /* tar_excl is true if cliplist lists files to be included.
1709 * Both 'I' and 'F' mean include. */
1710 tar_excl=tar_clipfl!='X';
1712 if (tar_clipfl=='F') {
1713 if (argc-Optind-1 != 1) {
1714 DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1718 /* Optind points at the tar output file, Optind+1 at the inclusion file. */
1719 if (! read_inclusion_file(argv[Optind+1])) {
1722 } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
1727 cliplist=argv+Optind+1;
1728 clipn=argc-Optind-1;
1731 if ((tmplist=SMB_MALLOC_ARRAY(char *,clipn)) == NULL) {
1732 DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n", clipn));
1736 for (clipcount = 0; clipcount < clipn; clipcount++) {
1738 DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1740 if ((tmpstr = (char *)SMB_MALLOC(strlen(cliplist[clipcount])+1)) == NULL) {
1741 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", clipcount));
1746 unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
1747 tmplist[clipcount] = tmpstr;
1748 DEBUG(5, ("Processed an item, %s\n", tmpstr));
1750 DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1754 must_free_cliplist = True;
1759 if (Optind+1<argc && tar_re_search && tar_clipfl != 'F') {
1760 /* Doing regular expression seaches not from an inclusion file. */
1761 clipn=argc-Optind-1;
1762 cliplist=argv+Optind+1;
1766 if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1767 /* Sets tar handle to either 0 or 1, as appropriate */
1768 tarhandle=(tar_type=='c');
1770 * Make sure that dbf points to stderr if we are using stdout for
1773 if (tarhandle == 1) {
1776 if (!argv[Optind]) {
1777 DEBUG(0,("Must specify tar filename\n"));
1780 if (!strcmp(argv[Optind], "-")) {
1785 if (tar_type=='c' && dry_run) {
1787 } else if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1)
1788 || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0)) {
1789 DEBUG(0,("Error opening local file %s - %s\n", argv[Optind], strerror(errno)));