manual edit of file works but creation via writeToFile: not working

Discussion in 'Mac Programming' started by prostuff1, Apr 9, 2012.

  1. macrumors 65816

    prostuff1

    Joined:
    Jul 29, 2005
    Location:
    Don't step into the kawoosh...
    #1
    So a little bit of a a story:

    I am writing myself a little helper application that edits a file (ui.properties) that belongs to the application CrashPlan.

    I have CrashPlan installed on a headless linux server and to be able to connect to it I need to edit the above ui.properties file (located at "/Applications/CrashPlan.app/Contents/Resources/Java/conf/ui.properties) and insert the line servicePort=4200. I then set up a tunnel from my Mac to the remote linux server and launch CrashPlan on my Mac.

    I have an appleScript that does the above and while it works, it is a little limited as I can not specify which linux server the ssh tunnel is supposed to go to. The idea behind this little helper app was so that I could specify a few other options.

    If I open the above ui.properties file in textmate, make the changes, close it, and launch CrashPlan everything works fine. If I use the appleScript I have it works fine. The issue I am having is that using the code I have that changes the file to what looks to be correct it does not seem to work.

    In the code below I am basically reading in the contents of the file, changing what I need to, deleting the old file, writing the changed stuff to a new file with the same name as the old one. It is not pretty right now but I will clean it up later.
    I have:
    Code:
    filesContent = [[NSString alloc] initWithContentsOfFile:crashplanUIFile];
                    NSLog(@"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
                    NSLog(@"files content = %@", filesContent);
                    NSLog(@"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
    
                    //NSString *newFilesContent = [[filesContent stringByAppendingString:@"servicePort=4200"] stringByAppendingFormat:@"\n"];
                    NSString *newFilesContent = [filesContent stringByReplacingOccurrencesOfString:@"#servicePort=4243" withString:@"servicePort=4200"];
                    NSLog(@"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
                    NSLog(@"New files content = %@", newFilesContent);
                    NSLog(@"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
    
                    NSError **error;
                    
                    if([[NSFileManager defaultManager] removeItemAtPath:crashplanUIFile error:error])
                    {
                        [newFilesContent writeToFile:crashplanUIFile atomically:TRUE encoding:NSUnicodeStringEncoding error:error];
                        NSDictionary *attributes;
                        NSNumber *permissions;
                        permissions = [NSNumber numberWithUnsignedLong: 444];
                        attributes = [NSDictionary dictionaryWithObject:permissions forKey:NSFilePosixPermissions];
                        // This actually sets the permissions
                        [[NSFileManager defaultManager] setAttributes:attributes ofItemAtPath:crashplanUIFile error:error];
                        NSLog(@"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
                        NSLog(@"Wrote file!!");
                        NSLog(@"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
                    }
    
    
    The appleScript code looks like this:
    Code:
    set theFile to "/Applications/CrashPlan.app/Contents/Resources/Java/conf/ui.properties" --give it the correct path to the file
    	try
    		set fileRef to (open for access (POSIX file theFile) with write permission) --open the file to for which we specified the path
    	on error errMsg number errNum
    		display dialog ("Open for Access, Error Number: " & errNum as string) & return & errMsg --handle any errors we have
    	end try
    	
    	set filesEOF to get eof fileRef -- find the end of the file
    	
    	try
    		set dataIn to read fileRef for filesEOF --setting point to insert the line at
    	on error errMsg number errNum
    		display dialog ("Read, Error Number: " & errNum as string) & return & errMsg --handle any errors
    	end try
    	set whereItIs to offset of "servicePort=4200" in dataIn --setting up the line to add/remove
    	
    	
    	if whereItIs = 0 then --the line does not exist
    		set dataOut to dataIn & ASCII character 10 & "servicePort=4200" & return --add the line to the end of the file
    		set msgToUser to "servicePort=4200 added" --set the message to display to the user
    		set determineActivate to true
    	else
    		copy characters 1 through (whereItIs - 1) of dataIn to dataOut -- the line does exist so "count backwards" and remove it
    		set msgToUser to "servicePort=4200 removed" --set the message that it was removed
    		set determineActivate to false
    		set startPoint to whereItIs + 16 -- "servicePort=4200"&return is 17 characters less one is 16
    		if startPoint < filesEOF then
    			set dataOut to dataOut & (characters startPoint thru filesEOF of dataIn)
    		end if
    	end if
    	
    	set dataOut to dataOut as text --setting the file again to the correct output
    	
    	set eof of fileRef to 0
    	
    	try
    		write dataOut to fileRef -- writing the data to the file
    	on error errMsg number errNum
    		display dialog ("Write, Error Number: " & errNum as string) & return & errMsg --check for any errors
    	end try
    	
    	
    	set eof of fileRef to (length of dataOut) --finding the end of the file
    	
    	
    	try
    		close access fileRef --close the file we opened
    	on error errMsg number errNum
    		display dialog ("Close, Error Number: " & errNum as string) & return & errMsg
    	end try
    
     
  2. macrumors 68000

    Sydde

    Joined:
    Aug 17, 2009
    #2
    IIRC, NSStringUnicodeEncoding is UTF16, is that what you want? Is that what you are getting (what does the file look like in hex view)? Try NSStringUTF8Encoding, see if that works.

    Also, I would use -initWithContentsOfFile:encoding:error:, as the method you are using is deprecated.
     
  3. thread starter macrumors 65816

    prostuff1

    Joined:
    Jul 29, 2005
    Location:
    Don't step into the kawoosh...
    #3
    Well, that seems to have done the trick. I changes the -initWith part and the Unicode (NSUTF8StringEncoding) and it seems to work now.

    Now to get -applicationWillTerminate: working so I can change the file contents back to what they were before the modification.
     
  4. macrumors 68000

    Sydde

    Joined:
    Aug 17, 2009
    #4
    You could just use a renaming convention. At launch, look for ".ui.properties", a hidden version of the file your app created: if it exists, rename ui.properties to ".def.ui.properties" and rename ".ui.properties" to "ui.properties". Alternately, if ".def.ui.properties" exists, do nothing (the existing version is the one you want because your app failed to quit correctly). If no hidden file exists, create your changes and rename ui.properties to .def.ui.properties before saving to ui.properties.

    At -applicationWillTerminate:, perform the appropriate rename swap. That way, you only actually have to write the changed file out once.
     
  5. macrumors 603

    Joined:
    Aug 9, 2009
    #5
    The red-hilited declaration using NSError is definitely wrong. If you're not going to use the returned-by-reference NSError*, then you're better off passing nil instead of an uninitialized pointer. You should read the Error Handling Programming Guide. At a minimum, read the section on "Using and Creating Error Objects", focusing on the ones that indirectly return NSError objects.

    The red-hilited 444 constant is probably wrong. If you intend to apply read-only permissions for all (user, group, other), the correct constant is 0444 (an octal constant). If you intend something else, please describe that intent. As given, 444 is a decimal constant, which is 0674 octal. I doubt that group-executable is useful, though the other permission-bits seem reasonable (user r/w, group r/w, others read-only).

    I also see that you're not checking the return value of writeToFile:, which is a boolean. It's nonsense to apply permissions if the write failed, so a conditional is called for.
     
  6. thread starter macrumors 65816

    prostuff1

    Joined:
    Jul 29, 2005
    Location:
    Don't step into the kawoosh...
    #6
    Thanks for the pointer I truly do appreciate it.

    As I mentioned it is not pretty nor complete. I was just trying to get some working code and the UTF8 comment made that happen. I have since done some more reading and had corrected the 444 permissions.

    The input on the NSError stuff is much appreciated. I will do some reading and see about changing/correcting that.
     

Share This Page