1 /* $Header: /home/cvs/wavplay/save_as.c,v 1.1.1.1 1999/11/21 19:50:56 wwg Exp $
2  * Warren W. Gay VE3WWG		Thu Apr 10 21:36:07 1997
3  *
4  * 	Save record.wav As... Dialog Callback [OK button]
5  *
6  * 	Copyright (C) 1997  Warren W. Gay VE3WWG
7  *
8  * This  program is free software; you can redistribute it and/or modify it
9  * under the  terms  of  the GNU General Public License as published by the
10  * Free Software Foundation version 2 of the License.
11  *
12  * This  program  is  distributed  in  the hope that it will be useful, but
13  * WITHOUT   ANY   WARRANTY;   without   even  the   implied   warranty  of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
15  * Public License for more details (see enclosed file COPYING).
16  *
17  * You  should have received a copy of the GNU General Public License along
18  * with this  program; if not, write to the Free Software Foundation, Inc.,
19  * 675 Mass Ave, Cambridge, MA 02139, USA.
20  *
21  * Send correspondance to:
22  *
23  * 	Warren W. Gay VE3WWG
24  *
25  * Email:
26  *	ve3wwg@yahoo.com
27  *	wgay@mackenziefinancial.com
28  *
29  * $Log: save_as.c,v $
30  * Revision 1.1.1.1  1999/11/21 19:50:56  wwg
31  * Import wavplay-1.3 into CVS
32  *
33  * Revision 1.3  1997/04/17 23:43:56  wwg
34  * Added #include <errno.h> for 1.0pl2 fix.
35  *
36  * Revision 1.2  1997/04/14 01:45:53  wwg
37  * Now automatically adds the "save as.." pathname to the list
38  * box, as a selection.
39  *
40  * Revision 1.1  1997/04/14 00:00:14  wwg
41  * Initial revision
42  */
43 static const char rcsid[] = "@(#)save_as.c $Revision: 1.1.1.1 $";
44 
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <unistd.h>
48 #include <fcntl.h>
49 #include <time.h>
50 #include <signal.h>
51 #include <string.h>
52 #include <errno.h>
53 #include <sys/types.h>
54 #include <sys/stat.h>
55 #include <assert.h>
56 
57 #include <Xm/Xm.h>
58 #include <Xm/FileSB.h>
59 #include <Xm/List.h>
60 
61 #include "xmsprint.h"
62 #include "xltwavplay.h"
63 #include "wavplay.h"
64 
65 /*
66  * This function is called when the recorded.wav file should be saved
67  * with a new pathname.
68  */
69 void
SaveAsDlgOKCB(Widget w,XtPointer client_data,XtPointer call_data)70 SaveAsDlgOKCB(Widget w,XtPointer client_data,XtPointer call_data) {
71 	XmListCallbackStruct *ptr = (XmListCallbackStruct *)call_data;
72 	char *path;						/* C string copy */
73 	struct stat dest_stat, src_stat;			/* stat() info on both paths */
74 	char bCopy = 0;						/* Move or Copy? */
75 	char buf[8192];						/* I/O Buffer */
76 	int ifd, ofd, n;					/* In/Out fds, n is byte count */
77 
78 	/*
79 	 * See if the recording exists to save:
80 	 */
81 	if ( stat(RECORD_PATH,&src_stat) != 0 ) {
82 		if ( errno == ENOENT )
83 			ReportErrorf("No file %s to 'save'.",RECORD_PATH);
84 		else	ReportErrorf("%s: doing stat on recorded.wav",sys_errlist[errno]);
85 		return;
86 	}
87 
88 	/*
89 	 * If per chance, recorded.wav is a symlink, then force a copy to the
90 	 * selected "Save As.." file.
91 	 */
92 	if ( S_ISLNK(src_stat.st_mode) )			/* Is recorded.wav a symlink? */
93 		bCopy = 1;					/* recording is a symlink to another file */
94 
95 	/*
96 	 * Get ASCII rendition of the selected pathname to save into:
97 	 */
98 	XmStringGetLtoR(ptr->item,XmSTRING_DEFAULT_CHARSET,&path);
99 
100 	/*
101 	 * See if the specified path exists already:
102 	 */
103 	if ( stat(path,&dest_stat) != 0 )			/* Stat save pathname.. */
104 		dest_stat.st_ctime = 0;				/* Mark as not found by stat() */
105 	else if ( !bCopy && dest_stat.st_dev == src_stat.st_dev ) {
106 		/*
107 		 * If here, we can entertain the possibility of just doing a mv
108 		 * to the destination pathname:
109 		 */
110 		if ( dest_stat.st_ino == src_stat.st_ino ) {
111 			ReportErrorf("You tried to save the file to itself (recorded.wav)");
112 			return;
113 		}
114 		/*
115 		 * Both are on same device, so delete destination file, and just move
116 		 * contents into place with link()
117 		 */
118 		if ( unlink(path) == 0 )
119 			dest_stat.st_ctime = 0;			/* File no longer exists */
120 		else	{
121 			ReportErrorf("%s: unlink(%s)\nWill attempt to do a copy instead, next.\n",path);
122 			bCopy = 1;
123 		}
124 	}
125 
126 	/*
127 	 * If the destination file already exists, see if its a symbolic link:
128 	 */
129 	if ( !bCopy && dest_stat.st_ctime != 0 ) {		/* if not copying, and path exists.. */
130 		if ( S_ISLNK(dest_stat.st_mode) )		/* is path a symlink? */
131 			bCopy = 1;				/* Destination is a symlink, do copy */
132 		else if ( dest_stat.st_dev != src_stat.st_dev )	/* are the files on different devs? */
133 			bCopy = 1;				/* Different devices: force copy */
134 	}
135 
136 	/*
137 	 * Move the file into place if we can.
138 	 */
139 	if ( !bCopy ) {
140 		if ( link(RECORD_PATH,path) == 0 ) {		/* mv by linking.. */
141 			if ( unlink(RECORD_PATH) != 0 )		/* And removing the old */
142 				ReportErrorf("%s: unlink(%s)",sys_errlist[errno]);
143 			goto rm;				/* Success (or mostly success) */
144 		} else	ReportErrorf("%s: link(%s,%s)\nWill try a copy next..",
145 				sys_errlist[errno],RECORD_PATH,path);
146 	}
147 
148 	/*
149 	 * Copy the file, if control passes to here:
150 	 */
151 	if ( (ifd = open(RECORD_PATH,O_RDONLY,0)) < 0 ) {
152 		ReportErrorf("%s: opening %s for read.",sys_errlist[errno],RECORD_PATH);
153 		goto xit;
154 	}
155 
156 	if ( (ofd = open(path,O_WRONLY|O_CREAT|O_TRUNC,0644)) < 0 ) {
157 		ReportErrorf("%s: opening %s for read.",sys_errlist[errno],path);
158 		close(ifd);
159 		goto xit;
160 	}
161 
162 	while ( (n = read(ifd,buf,sizeof buf)) > 0 )
163 		if ( write(ofd,buf,n) < 0 ) {
164 			ReportErrorf("%s: writing file %s for copy.",sys_errlist[errno],path);
165 			close(ifd);
166 			close(ofd);
167 			unlink(path);
168 			goto xit;
169 		}
170 
171 	if ( n < 0 ) {
172 		ReportErrorf("%s: reading file %s for copy.",sys_errlist[errno],RECORD_PATH);
173 		close(ifd);
174 		close(ofd);
175 		unlink(path);
176 		goto xit;
177 	}
178 
179 	if ( fsync(ofd) != 0 )
180 		ReportErrorf("%s: fsync(%s)",sys_errlist[errno],path);
181 	if ( close(ofd) == 0 )
182 		unlink(RECORD_PATH);		/* Delete recorded.wav if copy successful */
183 	close(ifd);
184 
185 	/*
186 	 * Success exit:
187 	 */
188 rm:	if ( stat(RECORD_PATH,&src_stat) == 0 )	/* If record.wav still exists.. */
189 		goto xit;			/* ..then don't unmanage this dialog yet */
190 
191 	if ( XtIsManaged(wSaveAsDlg) )		/* Safety test.. */
192 		XtUnmanageChild(wSaveAsDlg);	/* Now pop this dialog down */
193 
194 	/*
195 	 * Remove the recorded.wav pathname from the list box:
196 	 */
197 	if ( XmListItemExists(wSelectionsListBox,sRecorded_wav) != False )
198 		XmListDeleteItem(wSelectionsListBox,sRecorded_wav);
199 
200 	/*
201 	 * If the new pathname exists, add it to the list box:
202 	 */
203 xit:	if ( stat(path,&dest_stat) == 0 ) {
204 		if ( XmListItemExists(wSelectionsListBox,ptr->item) == False ) /* path */
205 			XmListAddItem(wSelectionsListBox,ptr->item,0);
206 	}
207 
208 	XtFree(path);				/* Free the allocated string and leave popped up */
209 }
210 
211 /* $Source: /home/cvs/wavplay/save_as.c,v $ */
212