"Never" is probably wrong; there are almost certainly cases where GOTO makes sense. More likely than not, though, is that if you find yourself choosing between GOTO and writing something complicated and hard to read, the problem is that your language is not expressive enough -- you are trying to do something that your language makes it hard for you to do.
In the example you gave, the problem is that C lacks something like exceptions and that there is no automatic way for cleanup code to be called. In Java, you can use try...finally, and so you can put your cleanup code in the finally block, and other languages have similar constructs. Unfortunately, in many languages, throwing an exception from a finally block will cause one of the exceptions (often the first) to be "forgotten," which is probably a bad thing; this is also hard to deal with in C, however, since an error that occurs in your cleanup code would need to be signaled somehow, but you can only return one value from the function -- so would you return the error that triggered the cleanup, or the error that resulted from the cleanup?
In the example you gave, the problem is that C lacks something like exceptions and that there is no automatic way for cleanup code to be called. In Java, you can use try...finally, and so you can put your cleanup code in the finally block, and other languages have similar constructs. Unfortunately, in many languages, throwing an exception from a finally block will cause one of the exceptions (often the first) to be "forgotten," which is probably a bad thing; this is also hard to deal with in C, however, since an error that occurs in your cleanup code would need to be signaled somehow, but you can only return one value from the function -- so would you return the error that triggered the cleanup, or the error that resulted from the cleanup?